home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / bildschirmschoner / fracblanker / source / fracblank.c next >
C/C++ Source or Header  |  1996-04-07  |  77KB  |  3,968 lines

  1. /*
  2. **    FracBlank - AmigaDOS 2.04 commodities utility screenblanker
  3. **
  4. **    Copyright © 1991-1995 by Olaf `Olsen' Barthel
  5. **        All Rights Reserved
  6. **
  7. **    Cosmic flame fractal code derived from xlock source code
  8. **
  9. **    Copyright © 1988-1991 by Patrick J. Naughton.
  10. */
  11.  
  12. #include <intuition/intuitionbase.h>
  13. #include <intuition/pointerclass.h>
  14. #include <intuition/sghooks.h>
  15.  
  16. #include <workbench/workbench.h>
  17. #include <workbench/startup.h>
  18.  
  19. #include <libraries/commodities.h>
  20. #include <libraries/asl.h>
  21.  
  22. #include <datatypes/pictureclass.h>
  23.  
  24. #include <graphics/gfxbase.h>
  25.  
  26. #include <hardware/custom.h>
  27.  
  28. #include <exec/interrupts.h>
  29. #include <exec/execbase.h>
  30. #include <exec/devices.h>
  31. #include <exec/memory.h>
  32.  
  33. #include <dos/dosextens.h>
  34. #include <dos/dostags.h>
  35. #include <dos/rdargs.h>
  36.  
  37. #include <clib/commodities_protos.h>
  38. #include <clib/intuition_protos.h>
  39. #include <clib/datatypes_protos.h>
  40. #include <clib/graphics_protos.h>
  41. #include <clib/utility_protos.h>
  42. #include <clib/keymap_protos.h>
  43. #include <clib/icon_protos.h>
  44. #include <clib/alib_protos.h>
  45. #include <clib/exec_protos.h>
  46. #include <clib/dos_protos.h>
  47. #include <clib/asl_protos.h>
  48.  
  49. #include <pragmas/datatypes_pragmas.h>
  50. #include <pragmas/utility_pragmas.h>
  51. #include <pragmas/keymap_pragmas.h>
  52. #include <pragmas/icon_pragmas.h>
  53. #include <pragmas/exec_pragmas.h>
  54. #include <pragmas/asl_pragmas.h>
  55.  
  56. #include <stdarg.h>
  57. #include <string.h>
  58. #include <stdlib.h>
  59. #include <math.h>
  60. #include <dos.h>
  61.  
  62. #include "gtlayout.h"
  63.  
  64.     // Use a simple address trick instead of the predefined
  65.     // address in amiga.lib
  66.  
  67. #ifndef custom
  68. #define custom (*(struct Custom *)0xDFF000)
  69. #endif    // custom
  70.  
  71.     // Command line arguments
  72.  
  73. enum    {    ARG_PRIORITY,
  74.         ARG_POPKEY,
  75.         ARG_POPUP,
  76.         ARG_BLANKSCREEN,
  77.         ARG_SAVESCREEN,
  78.         ARG_FRACTAL,
  79.         ARG_COLOUR,
  80.         ARG_DISPLAYMODE,
  81.         ARG_DEPTH,
  82.         ARG_SCREENTIMEOUT,
  83.         ARG_PATTERNTIMEOUT,
  84.         ARG_MAXRECURSION,
  85.         ARG_MAXDOTS,
  86.  
  87.         ARGCOUNT
  88.     };
  89.  
  90.     // Hotkey IDs
  91.  
  92. enum    {    POP_WINDOW,
  93.         BLANK_SCREEN,
  94.         SAVE_SCREEN
  95.     };
  96.  
  97.     // Gadget IDs
  98.  
  99. enum    {    GAD_HOTKEY=1000,
  100.         GAD_BLANKSCREEN,
  101.         GAD_SAVESCREEN,
  102.         GAD_MODE,
  103.         GAD_HIDE,
  104.         GAD_SAVE,
  105.         GAD_QUIT
  106.     };
  107.  
  108.     // Error codes
  109.  
  110. enum    {    ERR_SystemError    = 30000,    // CBERR_SYSERR
  111.         ERR_Duplicate,            // CBERR_DUP,
  112.         ERR_Version,            // CBERR_VERSION,
  113.  
  114.         ERR_BadFilter = 31000,        // COERR_BADFILTER,
  115.         ERR_BadType,            // COERR_BADTYPE
  116.  
  117.         ERR_NoIntuition = 32000,    // intuition.library didn't open
  118.         ERR_NoGfx,            // graphics.library didn't open
  119.         ERR_NoAsl,            // asl.library didn't open
  120.         ERR_NoCommodities,        // commodities.library didn't open
  121.         ERR_NoUtility,            // utility.library didn't open
  122.         ERR_NoIcon,            // icon.library didn't open
  123.         ERR_ScreenModeRequest,        // Couldn't allocate ScreenModeRequester
  124.         ERR_NoColours,            // Couldn't allocate colour table
  125.         ERR_NoPointer,            // Couldn't create transparent pointer
  126.         ERR_NoControlProcess,        // Couldn't create control process
  127.         ERR_NoMsgPort,            // Couldn't create msgport
  128.         ERR_NoWindow,            // Couldn't open window
  129.         ERR_NoKeymap,            // Couldn't open keymap.library
  130.         ERR_NoGTLayout,            // Couldn't open gtlayout.library
  131.     };
  132.  
  133.     // All the rawkey codes we know about
  134.  
  135. #define RAWKEY_CURSOR_UP    76
  136. #define RAWKEY_CURSOR_DOWN    77
  137. #define RAWKEY_CURSOR_RIGHT    78
  138. #define RAWKEY_CURSOR_LEFT    79
  139.  
  140. #define RAWKEY_F1        80
  141. #define RAWKEY_F2        81
  142. #define RAWKEY_F3        82
  143. #define RAWKEY_F4        83
  144. #define RAWKEY_F5        84
  145. #define RAWKEY_F6        85
  146. #define RAWKEY_F7        86
  147. #define RAWKEY_F8        87
  148. #define RAWKEY_F9        88
  149. #define RAWKEY_F10        89
  150.  
  151. #define RAWKEY_HELP        95
  152.  
  153.     // Some useful signals
  154.  
  155. #define SIG_FINISH    SIGBREAKF_CTRL_E
  156. #define SIG_BREAK    SIGBREAKF_CTRL_C
  157. #define SIG_CHANGE    SIGBREAKF_CTRL_D
  158. #define SIG_CYCLE    SIGBREAKF_CTRL_E
  159. #define SIG_START    SIGBREAKF_CTRL_F
  160. #define SIG_REFRESH    SIG_START
  161. #define SIG_WAKEUP    SIGBREAKF_CTRL_F
  162. #define SIG_HANDSHAKE    SIGF_SINGLE
  163. #define SIG_CX        (1L << CxPort -> mp_SigBit)
  164. #define SIG_WINDOW    (1L << Window -> UserPort -> mp_SigBit)
  165.  
  166.     // Fractal types
  167.  
  168. enum    {    FRACTAL_REAL_PLANE,
  169.         FRACTAL_COSMIC_FLAME,
  170.         FRACTAL_RANDOM
  171.     };
  172.  
  173.     // Colour modes
  174.  
  175. enum    {    COLOUR_CYCLE,
  176.         COLOUR_STATIC
  177.     };
  178.  
  179.     // A 96 bit colour entry
  180.  
  181. typedef struct ColourEntry
  182. {
  183.     ULONG            Red,
  184.                 Green,
  185.                 Blue;
  186. } ColourEntry;
  187.  
  188.     // A table of colour entries, ready for LoadRGB32()
  189.  
  190. typedef struct ColourTable
  191. {
  192.     WORD        NumColours,
  193.             FirstColour;
  194.  
  195.     ColourEntry    Entry[1];
  196.  
  197.     ULONG        Terminator;
  198. } ColourTable;
  199.  
  200.     // Spread a byte across a long word
  201.  
  202. #define SPREAD(v)    ((ULONG)(v) << 24 | (ULONG)(v) << 16 | (ULONG)(v) << 8 | (v))
  203.  
  204.     // Program revision tag
  205.  
  206. UBYTE             VersTag[] = "\0$VER: FracBlank 2.3 (9.3.95)";
  207.  
  208.     // Shared library identifiers
  209.  
  210. extern struct ExecBase    *SysBase;
  211.  
  212. struct IntuitionBase    *IntuitionBase;
  213. struct GfxBase        *GfxBase;
  214. struct Library        *CxBase,
  215.             *IconBase,
  216.             *AslBase,
  217.             *UtilityBase,
  218.             *DataTypesBase,
  219.             *KeymapBase,
  220.             *GTLayoutBase;
  221.  
  222.     // The main program
  223.  
  224. struct Process        *MainProcess;
  225. BOOL             PopUp;
  226.  
  227.     // BlankerEntry data
  228.  
  229. struct SignalSemaphore     BlankSemaphore;
  230. struct Hook         ScreenHook,
  231.              WindowHook;
  232. struct Task        *BlankTask;
  233. ULONG             CycleMask;
  234. LONG             CycleBit;
  235. struct Screen        *BlankScreen;
  236. struct Window        *BlankWindow;
  237. WORD             Width,
  238.              Height;
  239. struct RastPort        *RPort;
  240. struct ViewPort        *VPort;
  241. ULONG             Pen;
  242.  
  243.     // A blank pointer
  244.  
  245. APTR             Pointer;
  246. UWORD             Nothing;
  247. struct BitMap         PointerBitMap;
  248.  
  249.     // String editing hook
  250.  
  251. struct Hook         EditHook;
  252.  
  253.     // BlankerControl data
  254.  
  255. struct Process        *BlankerControlProcess;
  256.  
  257.     // Commodities interface data
  258.  
  259. struct MsgPort        *CxPort;
  260. CxObj            *Broker;
  261. ULONG             SpecialQualifier;
  262.  
  263.     // Declarations for cosmic flame blanker code
  264.  
  265. double             Flame[2][3][2];
  266. WORD             FlameLevel,
  267.              FlameAlternateForm;
  268. WORD             FlameWheel,
  269.              FlameColour;
  270. ULONG             FlamePoints;
  271. ULONG             MaxRecursionLevel    = 40,
  272.              MaxFlamePoints        = 200;
  273.  
  274.     // Key sequence buffers
  275.  
  276. UBYTE             HotkeyBuffer[256],
  277.              BlankScreenBuffer[256],
  278.              SaveScreenBuffer[256];
  279.  
  280.     // Screen and pattern change timeout
  281.  
  282. ULONG             ScreenCount    = 0,
  283.              PatternCount    = 0,
  284.              ScreenTimeout    = 60,
  285.              PatternTimeout    = 60;
  286.  
  287.     // Some kind of a semaphore to tell the blank task to stop drawing
  288.  
  289. BYTE             StopDrawing    = FALSE;
  290.  
  291.     // sin -45° = cos -45° (saves precious calculation time)
  292.  
  293. double             deg45;
  294.  
  295.     // In case we need to rescale things
  296.  
  297. double             VerticalScale;
  298.  
  299.     // The current colour mode
  300.  
  301. UBYTE             ColourMode = COLOUR_CYCLE;
  302.  
  303.     // The current fractal type
  304.  
  305. UBYTE             FractalType = FRACTAL_RANDOM;
  306.  
  307.     // Colour table data
  308.  
  309. UBYTE             Red[255],
  310.              Green[255],
  311.              Blue[255];
  312. WORD             MaxColour,
  313.              Wheel;
  314. ColourTable        *Colours;
  315.  
  316.     // User interface data
  317.  
  318. struct Window        *Window;
  319. LayoutHandle        *Handle;
  320.  
  321.     // Screen mode requester data
  322.  
  323. struct ScreenModeRequester    *ScreenModeRequest;
  324. BOOL             ResetRequest = FALSE;
  325. ULONG             DisplayID;
  326. WORD             DisplayDepth;
  327. WORD             Depth;
  328. UBYTE             DisplayModeBuffer[DISPLAYNAMELEN + 40];
  329.  
  330.     // The process responsible for saving the screen data to the clipboard
  331.  
  332. struct Process        *Saver;
  333.  
  334.     // A new broker definition, Commodities needs this
  335.  
  336. struct NewBroker NewBroker =
  337. {
  338.     NB_VERSION,
  339.     "FracBlank",
  340.     "Fractal screen blanker v2.3",
  341.     "Screen blanker",
  342.     NBU_NOTIFY | NBU_UNIQUE,
  343.     COF_SHOW_HIDE,
  344.     0,NULL,0
  345. };
  346.  
  347.     // Prototypes for this module
  348.  
  349. BOOL            GetModeName(ULONG Mode,STRPTR Buffer);
  350. struct Library *    SafeOpenLibrary(STRPTR Name,LONG Version);
  351. CxObj *            CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID);
  352. void            hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b);
  353. void            hsvramp(double h1,double s1,double b1,double h2,double s2,double b2,int count,UBYTE *red,UBYTE *green,UBYTE *blue);
  354. VOID            StuffChar(VOID);
  355. VOID __stdargs        SPrintf(STRPTR Buffer,STRPTR FormatString,...);
  356. LONG            Atol(STRPTR Buffer);
  357. STRPTR            ToolString(STRPTR *Array,STRPTR Match,STRPTR Default);
  358. LONG            ToolValue(STRPTR *Array,STRPTR Match,LONG Default);
  359. ULONG            BackfillDummy(VOID);
  360. VOID            RotatePalette(VOID);
  361. VOID            BlackScreen(VOID);
  362. VOID __saveds        BlankerControlEntry(VOID);
  363. ULONG            Random(ULONG MaxValue);
  364. VOID            MonoPlot(WORD Left,WORD Top);
  365. VOID            MultiPlot(ULONG Colour,WORD Left,WORD Top);
  366. VOID            RealPlane(VOID);
  367. BOOL            RecurseMono(double x,double y,WORD Level);
  368. BOOL            RecurseColour(double x,double y,WORD Level);
  369. VOID            CosmicFlame(VOID);
  370. VOID __saveds        BlankerEntry(VOID);
  371. VOID __saveds __stdargs    BlankerAction(CxMsg *CxMessage,CxObj *CxObject);
  372. VOID            ShutdownCx(VOID);
  373. WORD            GetSeconds(STRPTR String);
  374. LONG            SetupCx(VOID);
  375. VOID            HandleCxMsg(CxMsg *Message);
  376. LONG __saveds __stdargs    ShowTime(struct Gadget *SomeGadget,WORD Level);
  377. VOID            ShutdownWindow(VOID);
  378. BOOL            SetupWindow(VOID);
  379. VOID            CloseAll(LONG ReturnCode);
  380. VOID            OpenAll(int argc,char **argv);
  381. VOID            UpdateModeString(VOID);
  382. VOID            SaveOptions(char **argv);
  383. VOID __saveds        SaverEntry(VOID);
  384. ULONG            BuildMask(STRPTR Code);
  385. ULONG            AddQualifier(STRPTR Code,ULONG Qualifier);
  386. ULONG            SubQualifier(STRPTR Code,ULONG Qualifier);
  387. WORD __stdargs        ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...);
  388. VOID            ReportError(struct Window *Window,STRPTR Template,LONG Error);
  389. ULONG __saveds __asm    EditRoutine(register __a0 struct Hook *Hook,register __a2 struct SGWork *Work,register __a1 ULONG *Msg);
  390.  
  391.     /* EditRoutine():
  392.      *
  393.      *    A special string gadget editing routine for key
  394.      *    combination input.
  395.      */
  396.  
  397. ULONG __saveds __asm
  398. EditRoutine(register __a0 struct Hook *Hook,register __a2 struct SGWork *Work,register __a1 ULONG *Msg)
  399. {
  400.     struct InputEvent    Event;
  401.     ULONG            Qualifier;
  402.     UWORD            Code;
  403.     UBYTE            Key[10];
  404.     WORD            KeyLen;
  405.     STRPTR            KeyName;
  406.  
  407.         // If the gadget just got activated or the caps lock key
  408.         // is active, don't change anything
  409.  
  410.     if(*Msg == SGH_CLICK || (*Msg == SGH_KEY && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CAPSLOCK)))
  411.         return(TRUE);
  412.     else
  413.     {
  414.             // Complain if this is not what we expect to be fun
  415.  
  416.         if(*Msg != SGH_KEY)
  417.             return(FALSE);
  418.     }
  419.  
  420.         // Ditch the qualifier keys
  421.  
  422.     if(Work -> IEvent -> ie_Code >= 96 && Work -> IEvent -> ie_Code <= 103)
  423.     {
  424.         Work -> Actions    &= ~(SGA_USE | SGA_BEEP);
  425.  
  426.         return(TRUE);
  427.     }
  428.  
  429.         // Strip all the qualifiers we don't want
  430.  
  431.     Qualifier = Work -> IEvent -> ie_Qualifier & ~(IEQUALIFIER_REPEAT | IEQUALIFIER_INTERRUPT | IEQUALIFIER_MULTIBROADCAST | IEQUALIFIER_RELATIVEMOUSE);
  432.  
  433.         // Check for raw keys
  434.  
  435.     switch(Work -> IEvent -> ie_Code)
  436.     {
  437.         case RAWKEY_CURSOR_UP:
  438.         case RAWKEY_CURSOR_DOWN:
  439.         case RAWKEY_CURSOR_RIGHT:
  440.         case RAWKEY_CURSOR_LEFT:
  441.  
  442.                 // A cursor key was pressed, check if there
  443.                 // is probably some special feature involved
  444.  
  445.             if(!(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
  446.                 return(TRUE);
  447.  
  448.             // FALLS THROUGH TO:
  449.  
  450.         case RAWKEY_F1:
  451.         case RAWKEY_F2:
  452.         case RAWKEY_F3:
  453.         case RAWKEY_F4:
  454.         case RAWKEY_F5:
  455.         case RAWKEY_F6:
  456.         case RAWKEY_F7:
  457.         case RAWKEY_F8:
  458.         case RAWKEY_F9:
  459.         case RAWKEY_F10:
  460.  
  461.         case RAWKEY_HELP:
  462.  
  463.                 // Ok, so this is a raw key event
  464.  
  465.             Code    = Work -> IEvent -> ie_Code;
  466.             KeyLen    = 0;
  467.  
  468.             break;
  469.  
  470.         default:
  471.  
  472.                 // Make a copy of the inputevent and
  473.                 // clear the qualifier bits
  474.  
  475.             CopyMem(Work -> IEvent,&Event,sizeof(struct InputEvent));
  476.  
  477.             Event . ie_Qualifier = NULL;
  478.  
  479.             Code = 0;
  480.  
  481.                 // Translate the event
  482.  
  483.             if((KeyLen = MapRawKey(&Event,Key,10,NULL)) < 0)
  484.                 KeyLen = 10;
  485.  
  486.             break;
  487.     }
  488.  
  489.         // Is the user holding down a single Amiga key?
  490.  
  491.     if(KeyLen && (Qualifier & IEQUALIFIER_RCOMMAND) && !(Qualifier & ~IEQUALIFIER_RCOMMAND))
  492.     {
  493.         UBYTE Char = ToUpper(Key[0]);
  494.  
  495.             // Undo and clear are supported
  496.  
  497.         if(Char == 'Q' || Char == 'X')
  498.             return(TRUE);
  499.     }
  500.  
  501.         // Can we safely continue?
  502.  
  503.     if((!Code && !KeyLen) || KeyLen > 1 || (!Code && KeyLen && !Key[0]))
  504.     {
  505.         Work -> Actions    = (Work -> Actions & ~SGA_USE) | SGA_BEEP;
  506.  
  507.         return(TRUE);
  508.     }
  509.  
  510.         // Take care of special characters
  511.  
  512.     if(KeyLen)
  513.     {
  514.         STATIC struct { UBYTE Code; STRPTR Name; } KeyTable[] =
  515.         {
  516.             '\r',    "Return",
  517.             '\b',    "Backspace",
  518.             '\033',    "Escape",
  519.             ' ',    "Spacebar",
  520.             ',',    "Comma",
  521.             '\177',    "Delete",
  522.             '\t',    "Tab",
  523.  
  524.             0
  525.         };
  526.  
  527.         BOOL GotIt = FALSE;
  528.         WORD i;
  529.  
  530.             // Carriage return was pressed
  531.  
  532.         if(Key[0] == '\r')
  533.         {
  534.                 // This probably ends input
  535.  
  536.             if(!Qualifier)
  537.             {
  538.                 Work -> Actions    = (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_END;
  539.  
  540.                 return(TRUE);
  541.             }
  542.             else
  543.             {
  544.                     // Is this the enter key?
  545.  
  546.                 if(Qualifier & IEQUALIFIER_NUMERICPAD)
  547.                 {
  548.                     KeyName = "Enter";
  549.  
  550.                     Qualifier &= ~IEQUALIFIER_NUMERICPAD;
  551.  
  552.                     GotIt = TRUE;
  553.                 }
  554.             }
  555.         }
  556.  
  557.             // If this is just the tab key, pass it through cleanly
  558.  
  559.         if(Key[0] == '\t' && !(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
  560.             return(TRUE);
  561.  
  562.             // Now check for special characters
  563.  
  564.         Key[0] = ToUpper(Key[0]);
  565.  
  566.         if(!GotIt)
  567.         {
  568.             for(i = 0 ; KeyTable[i] . Code ; i++)
  569.             {
  570.                 if(KeyTable[i] . Code == Key[0])
  571.                 {
  572.                     KeyName = KeyTable[i] . Name;
  573.  
  574.                     GotIt = TRUE;
  575.  
  576.                     break;
  577.                 }
  578.             }
  579.         }
  580.  
  581.             // If no special character is involved,
  582.             // use the vanilla character code
  583.  
  584.         if(!GotIt)
  585.         {
  586.             if((Key[0] > ' ' && Key[0] < 127) || Key[0] >= 160)
  587.             {
  588.                 Key[1] = 0;
  589.  
  590.                 KeyName = Key;
  591.             }
  592.             else
  593.             {
  594.                 Work -> Actions    = (Work -> Actions & ~SGA_USE) | SGA_BEEP;
  595.  
  596.                 return(TRUE);
  597.             }
  598.         }
  599.     }
  600.     else
  601.     {
  602.             // Special raw key code table
  603.  
  604.         STATIC struct { UWORD Code; STRPTR Name; } RawTable[] =
  605.         {
  606.             RAWKEY_CURSOR_UP,    "Cursor_Up",
  607.             RAWKEY_CURSOR_DOWN,    "Cursor_Down",
  608.             RAWKEY_CURSOR_RIGHT,    "Cursor_Right",
  609.             RAWKEY_CURSOR_LEFT,    "Cursor_Left",
  610.  
  611.             RAWKEY_F1,        "F1",
  612.             RAWKEY_F2,        "F2",
  613.             RAWKEY_F3,        "F3",
  614.             RAWKEY_F4,        "F4",
  615.             RAWKEY_F5,        "F5",
  616.             RAWKEY_F6,        "F6",
  617.             RAWKEY_F7,        "F7",
  618.             RAWKEY_F8,        "F8",
  619.             RAWKEY_F9,        "F9",
  620.             RAWKEY_F10,        "F10",
  621.  
  622.             RAWKEY_HELP,        "Help",
  623.  
  624.             0
  625.         };
  626.  
  627.         WORD i;
  628.  
  629.             // One eventually must match
  630.  
  631.         for(i = 0 ; RawTable[i] . Code ; i++)
  632.         {
  633.             if(Code == RawTable[i] . Code)
  634.             {
  635.                 KeyName = RawTable[i] . Name;
  636.  
  637.                 break;
  638.             }
  639.         }
  640.     }
  641.  
  642.         // Take care of the qualifiers. Note that we do not distinguish
  643.         // between the left and right shift/alt keys
  644.  
  645.     if(Qualifier)
  646.     {
  647.         STATIC struct { ULONG Qualifier; STRPTR Name; } QualifierTable[] =
  648.         {
  649.             IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT,    "Shift ",
  650.             IEQUALIFIER_LALT | IEQUALIFIER_RALT,        "Alt ",
  651.             IEQUALIFIER_LCOMMAND,                "LAmiga ",
  652.             IEQUALIFIER_RCOMMAND,                "RAmiga ",
  653.             IEQUALIFIER_LEFTBUTTON,                "Left_Button ",
  654.             IEQUALIFIER_MIDBUTTON,                "Middle_Button ",
  655.             IEQUALIFIER_RBUTTON,                "Right_Button ",
  656.             IEQUALIFIER_NUMERICPAD,                "Numeric_Pad ",
  657.  
  658.             0
  659.         };
  660.  
  661.         WORD i;
  662.  
  663.             // Ok, now start building the string
  664.  
  665.         Work -> WorkBuffer[0] = 0;
  666.  
  667.         for(i = 0 ; QualifierTable[i] . Qualifier ; i++)
  668.         {
  669.             if(Qualifier & QualifierTable[i] . Qualifier)
  670.                 strcat(Work -> WorkBuffer,QualifierTable[i] . Name);
  671.         }
  672.  
  673.             // Add the key itself
  674.  
  675.         strcat(Work -> WorkBuffer,KeyName);
  676.  
  677.             // Update the work data
  678.  
  679.         Work -> NumChars    = strlen(Work -> WorkBuffer);
  680.         Work -> BufferPos    = Work -> NumChars;
  681.  
  682.             // Finished...
  683.  
  684.         Work -> Actions    = (Work -> Actions & ~(SGA_BEEP | SGA_PREVACTIVE | SGA_NEXTACTIVE | SGA_END)) | SGA_REDISPLAY | SGA_USE;
  685.     }
  686.     else
  687.         Work -> Actions    &= ~(SGA_USE | SGA_BEEP);
  688.  
  689.     return(TRUE);
  690. }
  691.  
  692.     /* ReportError(struct Window *Window,STRPTR Template,LONG Error):
  693.      *
  694.      *    Show an error message.
  695.      */
  696.  
  697. VOID
  698. ReportError(struct Window *Window,STRPTR Template,LONG Error)
  699. {
  700.     STATIC struct { LONG Error; STRPTR Code; } Table[] =
  701.     {
  702.         ERR_SystemError,        "Commodities system error; out of memory",
  703.         ERR_Duplicate,            "Commodities broker already exists",
  704.         ERR_Version,            "Commodities broker version not supported",
  705.  
  706.         ERR_BadFilter,            "Bad filter descriptor",
  707.         ERR_BadType,            "Bad type descriptor",
  708.  
  709.         ERR_NoIntuition,        "Could not open intuition.library v37",
  710.         ERR_NoGfx,            "Could not open graphics.library v39",
  711.         ERR_NoAsl,            "Could not open asl.library v38",
  712.         ERR_NoCommodities,        "Could not open commodities.library v37",
  713.         ERR_NoUtility,            "Could not open utility.library v37",
  714.         ERR_NoIcon,            "Could not open icon.library v37",
  715.         ERR_ScreenModeRequest,        "Could not allocate screen mode requester",
  716.         ERR_NoColours,            "Could not allocate colour table; out of memory",
  717.         ERR_NoPointer,            "Could not allocate mouse pointer; out of memory",
  718.         ERR_NoControlProcess,        "Could not create mouse blanker process",
  719.         ERR_NoMsgPort,            "Could not create message port",
  720.         ERR_NoWindow,            "Could not open window",
  721.         ERR_NoKeymap,            "Could not open keymap.library",
  722.         ERR_NoGTLayout,            "Could not open gtlayout.library v9",
  723.  
  724.         0,            NULL
  725.     };
  726.  
  727.     UBYTE    LocalBuffer[256];
  728.     STRPTR    Buffer;
  729.     BOOL    GotIt = FALSE;
  730.     LONG    i;
  731.  
  732.         // Look for the corresponding error message.
  733.  
  734.     for(i = 0 ; Table[i] . Error ; i++)
  735.     {
  736.         if(Error == Table[i] . Error)
  737.         {
  738.             Buffer = Table[i] . Code;
  739.  
  740.             GotIt = TRUE;
  741.  
  742.             break;
  743.         }
  744.     }
  745.  
  746.     if(!GotIt)
  747.     {
  748.         if(!Fault(Error,"",LocalBuffer,256))
  749.             return;
  750.  
  751.         Buffer = &LocalBuffer[2];
  752.     }
  753.  
  754.     if(!Template)
  755.         Template = Buffer;
  756.  
  757.     if(MainProcess -> pr_CLI && !Window)
  758.     {
  759.         Printf("FracBlank: ");
  760.         Printf(Template,Buffer);
  761.         Printf("\n");
  762.     }
  763.     else
  764.         ShowRequest(Window,Template,"Continue",Buffer);
  765. }
  766.  
  767.     /* ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...):
  768.      *
  769.      *    This routine shows an easy requester. If there is just one
  770.      *    button to be pressed, the user will be able to answer it
  771.      *    by pressing any key.
  772.      */
  773.  
  774. WORD __stdargs
  775. ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...)
  776. {
  777.     if(IntuitionBase)
  778.     {
  779.         struct EasyStruct    Easy;
  780.         va_list            VarArgs;
  781.         LONG            i,GadgetCount;
  782.  
  783.         for(i = GadgetCount = 0 ; i < strlen(Gadgets) ; i++)
  784.         {
  785.             if(Gadgets[i] == '|')
  786.                 GadgetCount++;
  787.         }
  788.  
  789.         Easy . es_StructSize    = sizeof(struct EasyStruct);
  790.         Easy . es_Flags        = NULL;
  791.         Easy . es_Title        = "Fractal screen blanker";
  792.         Easy . es_TextFormat    = Text;
  793.         Easy . es_GadgetFormat    = Gadgets;
  794.  
  795.         if(GadgetCount)
  796.         {
  797.             WORD Result;
  798.  
  799.             if(GTLayoutBase)
  800.                 LT_LockWindow(Window);
  801.  
  802.             va_start(VarArgs,Gadgets);
  803.             Result = EasyRequestArgs(Window,&Easy,NULL,VarArgs);
  804.             va_end(VarArgs);
  805.  
  806.             if(GTLayoutBase)
  807.                 LT_UnlockWindow(Window);
  808.  
  809.             return(Result);
  810.         }
  811.         else
  812.         {
  813.             struct Window *ReqWindow;
  814.  
  815.             if(GTLayoutBase)
  816.                 LT_LockWindow(Window);
  817.  
  818.             va_start(VarArgs,Gadgets);
  819.  
  820.             if(ReqWindow = BuildEasyRequestArgs(Window,&Easy,IDCMP_RAWKEY,VarArgs))
  821.             {
  822.                 ULONG    IDCMP;
  823.                 LONG    Result;
  824.  
  825.                 FOREVER
  826.                 {
  827.                     WaitPort(ReqWindow -> UserPort);
  828.  
  829.                     IDCMP = NULL;
  830.  
  831.                     Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
  832.  
  833.                     if(!Result || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
  834.                         break;
  835.                 }
  836.  
  837.                 FreeSysRequest(ReqWindow);
  838.             }
  839.  
  840.             va_end(VarArgs);
  841.  
  842.             if(GTLayoutBase)
  843.                 LT_UnlockWindow(Window);
  844.         }
  845.     }
  846.  
  847.     return(0);
  848. }
  849.  
  850.     /* BuildMask(STRPTR Code):
  851.      *
  852.      *    Build a mask of qualifiers covered by the given
  853.      *    code.
  854.      */
  855.  
  856. ULONG
  857. BuildMask(STRPTR Code)
  858. {
  859.     IX Expression;
  860.  
  861.     if(!ParseIX(Code,&Expression))
  862.     {
  863.         ULONG Mask = NULL,Bits = Expression . ix_Qualifier & Expression . ix_QualMask;
  864.  
  865.             // Are shift/caps lock keys involved?
  866.  
  867.         if(Bits & IXSYM_CAPSMASK)
  868.         {
  869.                 // Are both shift keys equivalent?
  870.  
  871.             if(Expression . ix_QualSame & IXSYM_SHIFT)
  872.                 Mask |= IXSYM_SHIFTMASK | (Bits & IEQUALIFIER_CAPSLOCK);
  873.             else
  874.             {
  875.                     // Are all shift/caps lock keys equivalent?
  876.  
  877.                 if(Expression . ix_QualSame & IXSYM_CAPS)
  878.                     Mask |= IXSYM_CAPSMASK;
  879.                 else
  880.                     Mask |= Bits & IXSYM_CAPSMASK;
  881.             }
  882.         }
  883.  
  884.             // Are alt keys involved?
  885.  
  886.         if(Bits & IXSYM_ALTMASK)
  887.         {
  888.                 // Are both alt keys equivalent?
  889.  
  890.             if(Expression . ix_QualSame & IXSYM_ALT)
  891.                 Mask |= IXSYM_ALTMASK;
  892.             else
  893.                 Mask |= Bits & IXSYM_ALTMASK;
  894.         }
  895.  
  896.             // Take care of the remaining qualifiers
  897.  
  898.         Mask |= Bits & ~(IXSYM_ALTMASK | IXSYM_CAPSMASK);
  899.  
  900.         return(Mask);
  901.     }
  902.     else
  903.         return(NULL);
  904. }
  905.  
  906.     /* AddQualifier(STRPTR Code,ULONG Qualifier):
  907.      *
  908.      *    Add to the qualifier mask.
  909.      */
  910.  
  911. ULONG
  912. AddQualifier(STRPTR Code,ULONG Qualifier)
  913. {
  914.     return(Qualifier | BuildMask(Code));
  915. }
  916.  
  917.     /* SubQualifier(STRPTR Code,ULONG Qualifier):
  918.      *
  919.      *    Remove keys from the qualifier mask.
  920.      */
  921.  
  922. ULONG
  923. SubQualifier(STRPTR Code,ULONG Qualifier)
  924. {
  925.     return(Qualifier & ~BuildMask(Code));
  926. }
  927.  
  928.     /* GetModeName(ULONG Mode,STRPTR Buffer):
  929.      *
  930.      *    This routine supplies the name for a DisplayID.
  931.      */
  932.  
  933. BOOL
  934. GetModeName(ULONG Mode,STRPTR Buffer)
  935. {
  936.     struct NameInfo NameInfo;
  937.  
  938.     if(GetDisplayInfoData(NULL,(APTR)&NameInfo,sizeof(struct NameInfo),DTAG_NAME,Mode))
  939.         strcpy(Buffer,NameInfo . Name);
  940.     else
  941.     {
  942.         struct DisplayInfo DisplayInfo;
  943.  
  944.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  945.         {
  946.             struct DimensionInfo DimensionInfo;
  947.  
  948.             if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  949.             {
  950.                 STRPTR MonitorName;
  951.  
  952.                 switch(Mode & MONITOR_ID_MASK)
  953.                 {
  954.                     case NTSC_MONITOR_ID:
  955.  
  956.                         MonitorName = "NTSC:";
  957.                         break;
  958.  
  959.                     case PAL_MONITOR_ID:
  960.  
  961.                         MonitorName = "PAL:";
  962.                         break;
  963.  
  964.                     case VGA_MONITOR_ID:
  965.  
  966.                         MonitorName = "VGA:";
  967.                         break;
  968.  
  969.                     case A2024_MONITOR_ID:
  970.  
  971.                         MonitorName = "A2024:";
  972.                         break;
  973.  
  974.                     default:
  975.  
  976.                         MonitorName = "";
  977.                         break;
  978.                 }
  979.  
  980.                 if(DisplayInfo . PropertyFlags & DIPF_IS_HAM)
  981.                     SPrintf(Buffer,"%s%ld × %ld HAM",MonitorName,DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1,DimensionInfo . TxtOScan . MaxY - DimensionInfo . TxtOScan . MinY + 1);
  982.                 else
  983.                     SPrintf(Buffer,"%s%ld × %ld",MonitorName,DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1,DimensionInfo . TxtOScan . MaxY - DimensionInfo . TxtOScan . MinY + 1);
  984.             }
  985.             else
  986.                 return(FALSE);
  987.         }
  988.         else
  989.             return(FALSE);
  990.     }
  991.  
  992.     return(TRUE);
  993. }
  994.  
  995.     /* SafeOpenLibrary(STRPTR Name,LONG Version):
  996.      *
  997.      *    Just like OpenLibrary, but makes sure that old
  998.      *    library versions get flushed from memory.
  999.      */
  1000.  
  1001. struct Library *
  1002. SafeOpenLibrary(STRPTR Name,LONG Version)
  1003. {
  1004.     struct Library *Base;
  1005.  
  1006.     Forbid();
  1007.  
  1008.     if(Base = (struct Library *)FindName(&SysBase -> LibList,FilePart(Name)))
  1009.     {
  1010.         if(Base -> lib_Version < Version)
  1011.             RemLibrary(Base);
  1012.     }
  1013.  
  1014.     Permit();
  1015.  
  1016.     return(OpenLibrary(Name,Version));
  1017. }
  1018.  
  1019.     /* CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID):
  1020.      *
  1021.      *    A replacement for the HotKey() routine found in
  1022.      *    amiga.lib.
  1023.      */
  1024.  
  1025. CxObj *
  1026. CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID)
  1027. {
  1028.     CxObj *Filter;
  1029.  
  1030.     if(Filter = CxFilter(Code))
  1031.     {
  1032.         CxObj *Sender;
  1033.  
  1034.         if(Sender = CxSender(Port,ID))
  1035.         {
  1036.             CxObj *Translator;
  1037.  
  1038.             AttachCxObj(Filter,Sender);
  1039.  
  1040.             if(Translator = CxTranslate(NULL))
  1041.             {
  1042.                 AttachCxObj(Filter,Translator);
  1043.  
  1044.                 if(!CxObjError(Filter))
  1045.                     return(Filter);
  1046.             }
  1047.         }
  1048.  
  1049.         DeleteCxObjAll(Filter);
  1050.     }
  1051.  
  1052.     return(NULL);
  1053. }
  1054.  
  1055.     /* hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b):
  1056.      *
  1057.      *    Convert HSV (hue, saturation, value) colour index into
  1058.      *    plain RGB (red, green, blue) colour space.
  1059.      */
  1060.  
  1061. void
  1062. hsv2rgb(double H,double S,double V,UBYTE *r,UBYTE *g,UBYTE *b)
  1063. {
  1064.     int i;
  1065.     double f,bb;
  1066.     UBYTE p,q,t;
  1067.  
  1068.     H -= floor(H);
  1069.     H *= 6.0;
  1070.     i = floor(H);
  1071.     f = H - (double)i;
  1072.     bb = 255.0 * V;
  1073.     p = (UBYTE)(bb * (1.0 - S));
  1074.     q = (UBYTE)(bb * (1.0 - (S * f)));
  1075.     t = (UBYTE)(bb * (1.0 - (S * (1.0 - f))));
  1076.  
  1077.     switch(i)
  1078.     {
  1079.         case 0:    *r = (UBYTE)bb;
  1080.             *g = t;
  1081.             *b = p;
  1082.             break;
  1083.  
  1084.         case 1:    *r = q;
  1085.             *g = (UBYTE)bb;
  1086.             *b = p;
  1087.             break;
  1088.  
  1089.         case 2:    *r = p;
  1090.             *g = (UBYTE)bb;
  1091.             *b = t;
  1092.             break;
  1093.  
  1094.         case 3:    *r = p;
  1095.             *g = q;
  1096.             *b = (UBYTE)bb;
  1097.             break;
  1098.  
  1099.         case 4:    *r = t;
  1100.             *g = p;
  1101.             *b = (UBYTE)bb;
  1102.             break;
  1103.  
  1104.         case 5:    *r = (UBYTE)bb;
  1105.             *g = p;
  1106.             *b = q;
  1107.             break;
  1108.     }
  1109. }
  1110.  
  1111.     /* hsvramp():
  1112.      *
  1113.      *    Creates a ramp within HSV colour space, showing all
  1114.      *    colours of the HSV circle.
  1115.      */
  1116.  
  1117. void
  1118. hsvramp(double h1,double s1,double b1,double h2,double s2,double b2,int count,UBYTE *red,UBYTE *green,UBYTE *blue)
  1119. {
  1120.     double dh,ds,db;
  1121.  
  1122.     dh = (h2 - h1) / count;
  1123.     ds = (s2 - s1) / count;
  1124.     db = (b2 - b1) / count;
  1125.  
  1126.     while(count--)
  1127.     {
  1128.         hsv2rgb(h1,s1,b1,red++,green++,blue++);
  1129.  
  1130.         h1 += dh;
  1131.         s1 += ds;
  1132.         b1 += db;
  1133.     }
  1134. }
  1135.  
  1136. VOID
  1137. StuffChar()
  1138. {
  1139.     __emit(0x16C0);    // MOVE D0,(A3)+
  1140. }
  1141.  
  1142.     /* SPrintf(STRPTR Buffer,STRPTR FormatString,...):
  1143.      *
  1144.      *    String formatting routine, similar to sprintf().
  1145.      */
  1146.  
  1147. VOID __stdargs
  1148. SPrintf(STRPTR Buffer,STRPTR FormatString,...)
  1149. {
  1150.     va_list VarArgs;
  1151.  
  1152.     va_start(VarArgs,FormatString);
  1153.     RawDoFmt(FormatString,VarArgs,(VOID (*)())StuffChar,Buffer);
  1154.     va_end(VarArgs);
  1155. }
  1156.  
  1157.     /* Atol(STRPTR Buffer):
  1158.      *
  1159.      *    Convert a string into a long word.
  1160.      */
  1161.  
  1162. LONG
  1163. Atol(STRPTR Buffer)
  1164. {
  1165.     LONG Result;
  1166.  
  1167.     StrToLong(Buffer,&Result);
  1168.  
  1169.     return(Result);
  1170. }
  1171.  
  1172.     /* ToolString(STRPTR *Array,STRPTR Match,STRPTR Default):
  1173.      *
  1174.      *    Return the matching tooltype value, if available.
  1175.      *    Otherwise do with the default value.
  1176.      */
  1177.  
  1178. STRPTR
  1179. ToolString(STRPTR *Array,STRPTR Match,STRPTR Default)
  1180. {
  1181.     if(Array)
  1182.     {
  1183.         STRPTR String;
  1184.  
  1185.         if(String = FindToolType(Array,Match))
  1186.             return(String);
  1187.     }
  1188.  
  1189.     return(Default);
  1190. }
  1191.  
  1192.     /* ToolValue(STRPTR *Array,STRPTR Match,LONG Default):
  1193.      *
  1194.      *    Return the matching tooltype value, if available.
  1195.      *    Otherwise do with the default value.
  1196.      */
  1197.  
  1198. LONG
  1199. ToolValue(STRPTR *Array,STRPTR Match,LONG Default)
  1200. {
  1201.     if(Array)
  1202.     {
  1203.         STRPTR String;
  1204.  
  1205.         if(String = FindToolType(Array,Match))
  1206.         {
  1207.             LONG Result;
  1208.  
  1209.             if(StrToLong(String,&Result) > 0)
  1210.                 return(Result);
  1211.         }
  1212.     }
  1213.  
  1214.     return(Default);
  1215. }
  1216.  
  1217.     /* BackfillDummy():
  1218.      *
  1219.      *    A no-op backfill routine, we'll clear the screen manually.
  1220.      */
  1221.  
  1222. ULONG
  1223. BackfillDummy()
  1224. {
  1225.     return(TRUE);
  1226. }
  1227.  
  1228.     /* RotatePalette():
  1229.      *
  1230.      *    Fill in the screen palette with new data.
  1231.      */
  1232.  
  1233. VOID
  1234. RotatePalette()
  1235. {
  1236.     WORD i,Index = Wheel;
  1237.  
  1238.     for(i = 1 ; i <= MaxColour ; i++)
  1239.     {
  1240.         Colours -> Entry[i] . Red    = SPREAD(Red[Index]);
  1241.         Colours -> Entry[i] . Green    = SPREAD(Green[Index]);
  1242.         Colours -> Entry[i] . Blue    = SPREAD(Blue[Index]);
  1243.  
  1244.         Index = (Index + 1) % MaxColour;
  1245.     }
  1246.  
  1247.         // Terminate the table, just in case...
  1248.  
  1249.     Colours -> Entry[Colours -> NumColours] . Red = 0;
  1250. }
  1251.  
  1252.     /* BlackScreen():
  1253.      *
  1254.      *    Clear the screen, this is accomplished by first setting the
  1255.      *    screen colours to black, clearing the screen and finally
  1256.      *    restoring the palette.
  1257.      */
  1258.  
  1259. VOID
  1260. BlackScreen()
  1261. {
  1262.     WORD Count;
  1263.  
  1264.     Count = Colours -> NumColours;
  1265.  
  1266.     Colours -> NumColours = MaxColour + 1;
  1267.  
  1268.     memset(&Colours -> Entry[0],0,256 * sizeof(ColourEntry));
  1269.  
  1270.     LoadRGB32(VPort,(ULONG *)Colours);
  1271.  
  1272.     SetRast(RPort,0);
  1273.  
  1274.     Colours -> NumColours = Count;
  1275.  
  1276.     RotatePalette();
  1277.  
  1278.     LoadRGB32(VPort,(ULONG *)Colours);
  1279. }
  1280.  
  1281.     /* BlankerControlEntry():
  1282.      *
  1283.      *    The screen blanker control task.
  1284.      */
  1285.  
  1286. VOID __saveds
  1287. BlankerControlEntry()
  1288. {
  1289.     ULONG SignalSet;
  1290.  
  1291.     Forbid();
  1292.  
  1293.         // Ring back...
  1294.  
  1295.     Signal(MainProcess,SIG_HANDSHAKE);
  1296.  
  1297.     FOREVER
  1298.     {
  1299.             // Wait for something to happen
  1300.  
  1301.         SignalSet = Wait(SIG_BREAK | SIG_START | SIG_CHANGE | SIG_FINISH);
  1302.  
  1303.             // Remove both the screen and the blanker task?
  1304.  
  1305.         if(SignalSet & (SIG_BREAK | SIG_FINISH))
  1306.         {
  1307.             ObtainSemaphore(&BlankSemaphore);
  1308.  
  1309.             if(BlankScreen)
  1310.                 ScreenToBack(BlankScreen);
  1311.  
  1312.                 // Remove the blanker task
  1313.  
  1314.             if(BlankTask)
  1315.             {
  1316.                 SetSignal(0,SIG_HANDSHAKE);
  1317.  
  1318.                     // Tell the blanker task to shut down
  1319.  
  1320.                 Signal(BlankTask,SIG_BREAK);
  1321.  
  1322.                     // Move the blanker task priority up,
  1323.                     // we don't want the low priority task
  1324.                     // to wait until some high priority task
  1325.                     // yields CPU time
  1326.  
  1327.                 SetTaskPri(BlankTask,127);
  1328.  
  1329.                     // Wait for handshake signal...
  1330.  
  1331.                 Wait(SIG_HANDSHAKE);
  1332.  
  1333.                     // He's dead, Jim
  1334.  
  1335.                 BlankTask = NULL;
  1336.             }
  1337.  
  1338.                 // Close the blanker screen
  1339.  
  1340.             if(BlankScreen)
  1341.             {
  1342.                 ScreenToBack(BlankScreen);
  1343.  
  1344.                 CloseWindow(BlankWindow);
  1345.  
  1346.                 BlankWindow = NULL;
  1347.  
  1348.                 CloseScreen(BlankScreen);
  1349.  
  1350.                 BlankScreen = NULL;
  1351.             }
  1352.  
  1353.             ReleaseSemaphore(&BlankSemaphore);
  1354.  
  1355.             SignalSet &= ~(SIG_CHANGE | SIG_START);
  1356.         }
  1357.  
  1358.             // Leave the town?
  1359.  
  1360.         if(SignalSet & SIG_FINISH)
  1361.             break;
  1362.  
  1363.             // Start the screen blanker?
  1364.  
  1365.         if(SignalSet & SIG_START)
  1366.         {
  1367.                 // Is the screen already open?
  1368.  
  1369.             if(!BlankScreen)
  1370.             {
  1371.                 ULONG LocalID;
  1372.  
  1373.                     // Use the default public screen display ID
  1374.                     // if necessary
  1375.  
  1376.                 if(DisplayID == INVALID_ID || (ModeNotAvailable(DisplayID) & ~DI_AVAIL_NOTWITHGENLOCK))
  1377.                 {
  1378.                     struct Screen *PubScreen = LockPubScreen(NULL);
  1379.  
  1380.                     if(PubScreen)
  1381.                     {
  1382.                         LocalID = GetVPModeID(&PubScreen -> ViewPort);
  1383.  
  1384.                         UnlockPubScreen(NULL,PubScreen);
  1385.                     }
  1386.                     else
  1387.                         LocalID = INVALID_ID;
  1388.                 }
  1389.                 else
  1390.                     LocalID = DisplayID;
  1391.  
  1392.                     // Did we get a valid ID?
  1393.  
  1394.                 if(LocalID != INVALID_ID)
  1395.                 {
  1396.                     WORD            LocalDepth;
  1397.                     struct DimensionInfo    DimensionInfo;
  1398.                     struct DisplayInfo    DisplayInfo;
  1399.  
  1400.                         // Choose the right display depth
  1401.  
  1402.                     LocalDepth = Depth;
  1403.  
  1404.                     if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(DimensionInfo),DTAG_DIMS,LocalID))
  1405.                     {
  1406.                         if(!LocalDepth)
  1407.                         {
  1408.                             if((LocalDepth = DimensionInfo . MaxDepth) > 8)
  1409.                                 LocalDepth = 8;
  1410.                         }
  1411.                         else
  1412.                         {
  1413.                             if(LocalDepth > DimensionInfo . MaxDepth)
  1414.                                 LocalDepth = DimensionInfo . MaxDepth;
  1415.                         }
  1416.                     }
  1417.                     else
  1418.                     {
  1419.                         if(!LocalDepth)
  1420.                             LocalDepth = 2;
  1421.                     }
  1422.  
  1423.                         // Compensate for the display aspect ratio
  1424.  
  1425.                     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(DisplayInfo),DTAG_DISP,LocalID))
  1426.                     {
  1427.                         if(DisplayInfo . Resolution . y)
  1428.                         {
  1429.                             double x,y;
  1430.  
  1431.                             x = (double)DisplayInfo . Resolution . x;
  1432.                             y = (double)DisplayInfo . Resolution . y;
  1433.  
  1434.                             VerticalScale = x / y;
  1435.                         }
  1436.                         else
  1437.                             VerticalScale = 1.0;
  1438.                     }
  1439.                     else
  1440.                         VerticalScale = 1.0;
  1441.  
  1442.                         // Set the colour table to black
  1443.  
  1444.                     MaxColour = (1 << LocalDepth) - 1;
  1445.  
  1446.                     Colours -> NumColours = MaxColour + 1;
  1447.  
  1448.                     memset(&Colours -> Entry[0],0,256 * sizeof(ColourEntry));
  1449.  
  1450.                         // Now open the screen and the window
  1451.  
  1452.                     ObtainSemaphore(&BlankSemaphore);
  1453.  
  1454.                     if(BlankScreen = OpenScreenTags(NULL,
  1455.                         SA_Behind,    TRUE,
  1456.                         SA_Quiet,    TRUE,
  1457.                         SA_DisplayID,    LocalID,
  1458.                         SA_Overscan,    OSCAN_MAX,
  1459.                         SA_Depth,    LocalDepth,
  1460.                         SA_ShowTitle,    FALSE,
  1461.                         SA_BackFill,    &ScreenHook,
  1462.                         SA_Colors32,    Colours,
  1463.                         SA_Draggable,    FALSE,
  1464.                         SA_Exclusive,    TRUE,
  1465.                     TAG_DONE))
  1466.                     {
  1467.                         VPort    = &BlankScreen -> ViewPort;
  1468.                         Width    = BlankScreen -> Width;
  1469.                         Height    = BlankScreen -> Height;
  1470.  
  1471.                             // To keep the ball rolling...
  1472.  
  1473.                         if((DisplayDepth = LocalDepth) == 1)
  1474.                         {
  1475.                             MaxColour = 255;
  1476.  
  1477.                             Colours -> NumColours = 2;
  1478.                         }
  1479.  
  1480.                             // Create a nice colour table
  1481.  
  1482.                         hsvramp(0.0,1.0,1.0,1.0,1.0,1.0,MaxColour,Red,Green,Blue);
  1483.  
  1484.                         Wheel = Random(MaxColour);
  1485.  
  1486.                         RotatePalette();
  1487.  
  1488.                             // Open the window
  1489.  
  1490.                         if(BlankWindow = OpenWindowTags(NULL,
  1491.                             WA_Left,        0,
  1492.                             WA_Top,            0,
  1493.                             WA_Width,        Width,
  1494.                             WA_Height,        Height,
  1495.                             WA_Backdrop,        TRUE,
  1496.                             WA_Borderless,        TRUE,
  1497.                             WA_Pointer,        Pointer,
  1498.                             WA_CustomScreen,    BlankScreen,
  1499.                             WA_Activate,        TRUE,
  1500.                             WA_RMBTrap,        TRUE,
  1501.                             WA_BackFill,        &WindowHook,
  1502.                         TAG_DONE))
  1503.                         {
  1504.                             RPort = BlankWindow -> RPort;
  1505.  
  1506.                             SetABPenDrMd(RPort,Pen = 1,0,JAM1);
  1507.  
  1508.                                 // Clear the screen
  1509.  
  1510.                             SetRast(RPort,0);
  1511.  
  1512.                             LoadRGB32(VPort,(ULONG *)Colours);
  1513.  
  1514.                                 // Display the screen
  1515.  
  1516.                             ScreenToFront(BlankScreen);
  1517.  
  1518.                             PatternCount = 0;
  1519.  
  1520.                                 // Wait for something to happen
  1521.  
  1522.                             Forbid();
  1523.  
  1524.                             BlankTask = (struct Task *)CreateTask("« FracBlank BlankerEntry Task »",127,BlankerEntry,4096 + 400 * MaxRecursionLevel);
  1525.  
  1526.                             SetSignal(0,SIG_HANDSHAKE);
  1527.  
  1528.                             Wait(SIG_HANDSHAKE);
  1529.  
  1530.                             Permit();
  1531.                         }
  1532.                         else
  1533.                         {
  1534.                             CloseScreen(BlankScreen);
  1535.  
  1536.                             BlankScreen = NULL;
  1537.                         }
  1538.                     }
  1539.                 }
  1540.  
  1541.                 ReleaseSemaphore(&BlankSemaphore);
  1542.             }
  1543.             else
  1544.             {
  1545.                     // Push the blanker screen to the front if necessary
  1546.  
  1547.                 if(BlankScreen -> TopEdge > 0)
  1548.                     MoveScreen(BlankScreen,0,-BlankScreen -> TopEdge);
  1549.  
  1550.                 if(IntuitionBase -> FirstScreen != BlankScreen)
  1551.                     ScreenToFront(BlankScreen);
  1552.  
  1553.                 if(IntuitionBase -> ActiveWindow != BlankWindow)
  1554.                     ActivateWindow(BlankWindow);
  1555.             }
  1556.  
  1557.             SignalSet &= ~SIG_CHANGE;
  1558.         }
  1559.  
  1560.             // Change the patterns?
  1561.  
  1562.         if(SignalSet & SIG_CHANGE)
  1563.         {
  1564.             if(BlankTask)
  1565.             {
  1566.                     // Stop drawing patterns
  1567.  
  1568.                 StopDrawing = TRUE;
  1569.  
  1570.                 Signal(BlankTask,SIG_CHANGE);
  1571.             }
  1572.         }
  1573.     }
  1574.  
  1575.     BlankerControlProcess = NULL;
  1576.  
  1577.     Signal(MainProcess,SIG_HANDSHAKE);
  1578. }
  1579.  
  1580.     /* Random(ULONG MaxValue):
  1581.      *
  1582.      *    Simple random number generation routine.
  1583.      */
  1584.  
  1585. ULONG
  1586. Random(ULONG MaxValue)
  1587. {
  1588.     if(MaxValue)
  1589.     {
  1590.         STATIC ULONG RandomSeed = 3735879991;
  1591.  
  1592.         RandomSeed = RandomSeed * custom . vhposr + 3780343439;
  1593.  
  1594.         return(RandomSeed % MaxValue);
  1595.     }
  1596.     else
  1597.         return(0);
  1598. }
  1599.  
  1600.     /* MonoPlot(WORD Left,WORD Top):
  1601.      *
  1602.      *    Set a pixel somewhere on the screen.
  1603.      */
  1604.  
  1605. VOID
  1606. MonoPlot(WORD Left,WORD Top)
  1607. {
  1608.     if(Left >= 0 && Left < Width && Top >= 0 && Top < Height)
  1609.         WritePixel(RPort,Left,Top);
  1610. }
  1611.  
  1612.     /* MultiPlot(ULONG Colour,WORD Left,WORD Top):
  1613.      *
  1614.      *    Set a coloured pixel somewhere on the screen.
  1615.      */
  1616.  
  1617. VOID
  1618. MultiPlot(ULONG Colour,WORD Left,WORD Top)
  1619. {
  1620.     if(Left >= 0 && Left < Width && Top >= 0 && Top < Height)
  1621.     {
  1622.         if(Pen != Colour)
  1623.             SetAPen(RPort,Pen = Colour);
  1624.  
  1625.         WritePixel(RPort,Left,Top);
  1626.     }
  1627. }
  1628.  
  1629.     /* RealPlane():
  1630.      *
  1631.      *    Draw real plane fractals.
  1632.      */
  1633.  
  1634. VOID
  1635. RealPlane()
  1636. {
  1637.     UWORD    OffsetX = Width / 2,OffsetY = Height / 2;
  1638.     ULONG    Signals;
  1639.     double    x = 0,y = 0,yy,a,b,c,sx,sy,mag;
  1640.  
  1641.         // Are we running in monochrome mode?
  1642.  
  1643.     if(DisplayDepth == 1)
  1644.     {
  1645.             // Provide starting numbers for the fractal
  1646.             // parameters
  1647.  
  1648.         a = (double)(Random(700) + 5) / 100;
  1649.         b = (double)(Random(190) + 5) / 100;
  1650.         c = (double)(Random( 90) + 5) / 100;
  1651.  
  1652.         mag = (double)(1 << (Random(6) + 2)) * deg45;
  1653.  
  1654.             // Go into fractal generation loop
  1655.  
  1656.         FOREVER
  1657.         {
  1658.             Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  1659.  
  1660.                 // Are we to shut down?
  1661.  
  1662.             if(Signals & SIG_BREAK)
  1663.             {
  1664.                 Forbid();
  1665.  
  1666.                 Signal(BlankerControlProcess,SIG_HANDSHAKE);
  1667.  
  1668.                 FreeSignal(CycleBit);
  1669.  
  1670.                 RemTask(NULL);
  1671.             }
  1672.  
  1673.                 /* The original formula looks like
  1674.                  * this:
  1675.                  *                                    ½
  1676.                  *    x = y - SIGN(x) × ABS(b × x - c)
  1677.                  *    y = a - x
  1678.                  *
  1679.                  * I have split the calculation into
  1680.                  * several steps to save time and
  1681.                  * variables.
  1682.                  */
  1683.  
  1684.             yy = a - x;
  1685.  
  1686.             if(x < 0)
  1687.                 x = y + sqrt(fabs(b * x - c));
  1688.             else
  1689.                 x = y - sqrt(fabs(b * x - c));
  1690.  
  1691.             y = yy;
  1692.  
  1693.                 /* The resulting image appears to have
  1694.                  * been rotated by 45°, so we'll
  1695.                  * rotate the pixel coordinates by -45°
  1696.                  *
  1697.                  *    x =  x × cos(alpha) + y × sin(alpha)
  1698.                  *    y = -x × sin(alpha) + y × cos(alpha)
  1699.                  *
  1700.                  * We also magnify the image (i.e. the
  1701.                  * distribution of pixels) in the following
  1702.                  * lines.
  1703.                  */
  1704.  
  1705.             sx = mag *                 ( x + y);
  1706.             sy = mag * VerticalScale * (-x + y);
  1707.  
  1708.                 // If the pixel happens to reside within
  1709.                 // the boundaries of the screen, draw it.
  1710.  
  1711.             MonoPlot((WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
  1712.  
  1713.                 // Change the pattern?
  1714.  
  1715.             if(Signals & SIG_CHANGE)
  1716.             {
  1717.                 BlackScreen();
  1718.  
  1719.                 StopDrawing = FALSE;
  1720.  
  1721.                 x = y = 0;
  1722.  
  1723.                 a = (double)(Random(700) + 5) / 100;
  1724.                 b = (double)(Random(190) + 5) / 100;
  1725.                 c = (double)(Random( 90) + 5) / 100;
  1726.  
  1727.                 mag = (double)(1 << (Random(6) + 2)) * deg45;
  1728.  
  1729.                 Signals &= ~CycleMask;
  1730.             }
  1731.  
  1732.                 // Cycle the colours?
  1733.  
  1734.             if(Signals & CycleMask)
  1735.             {
  1736.                 LoadRGB32(VPort,(ULONG *)Colours);
  1737.  
  1738.                 Wheel = (Wheel + 1) % MaxColour;
  1739.  
  1740.                 RotatePalette();
  1741.             }
  1742.         }
  1743.     }
  1744.     else
  1745.     {
  1746.         UWORD         Count = 0;
  1747.         WORD         Colour;
  1748.  
  1749.         a = (double)(Random(700) + 5) / 100;
  1750.         b = (double)(Random(190) + 5) / 100;
  1751.         c = (double)(Random( 90) + 5) / 100;
  1752.  
  1753.         mag = (double)(1 << (Random(6) + 2)) * deg45;
  1754.  
  1755.         Colour = Random(MaxColour - 1) + 1;
  1756.  
  1757.         FOREVER
  1758.         {
  1759.             Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  1760.  
  1761.             if(Signals & SIG_BREAK)
  1762.             {
  1763.                 Forbid();
  1764.  
  1765.                 Signal(BlankerControlProcess,SIG_HANDSHAKE);
  1766.  
  1767.                 FreeSignal(CycleBit);
  1768.  
  1769.                 RemTask(NULL);
  1770.             }
  1771.  
  1772.             yy = a - x;
  1773.  
  1774.             if(x < 0)
  1775.                 x = y + sqrt(fabs(b * x - c));
  1776.             else
  1777.                 x = y - sqrt(fabs(b * x - c));
  1778.  
  1779.             y = yy;
  1780.  
  1781.             sx = mag *                 ( x + y);
  1782.             sy = mag * VerticalScale * (-x + y);
  1783.  
  1784.             MultiPlot(Colour,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
  1785.  
  1786.                 /* Oh well, it's not that easy to
  1787.                  * produce decent colour values for
  1788.                  * the pixels to be rendered.
  1789.                  *
  1790.                  * The following statement will change
  1791.                  * the current drawing pen after exactly
  1792.                  * 1200 pixels have been rendered and will
  1793.                  * pick a new colour between 1 and 31.
  1794.                  */
  1795.  
  1796.             if(Count++ >= 1200)
  1797.             {
  1798.                 WORD NewColour;
  1799.  
  1800.                 Count = 0;
  1801.  
  1802.                 do
  1803.                     NewColour = Random(MaxColour - 1) + 1;
  1804.                 while(NewColour == Colour);
  1805.  
  1806.                 Colour = NewColour;
  1807.             }
  1808.  
  1809.             if(Signals & SIG_CHANGE)
  1810.             {
  1811.                 BlackScreen();
  1812.  
  1813.                 StopDrawing = FALSE;
  1814.  
  1815.                 x = y = 0;
  1816.  
  1817.                 a = (double)(Random(700) + 5) / 100;
  1818.                 b = (double)(Random(190) + 5) / 100;
  1819.                 c = (double)(Random( 90) + 5) / 100;
  1820.  
  1821.                 mag = (double)(1 << (Random(6) + 2)) * deg45;
  1822.  
  1823.                 Signals &= ~CycleMask;
  1824.             }
  1825.  
  1826.             if(Signals & CycleMask)
  1827.             {
  1828.                 LoadRGB32(VPort,(ULONG *)Colours);
  1829.  
  1830.                 Wheel = (Wheel + 1) % MaxColour;
  1831.  
  1832.                 RotatePalette();
  1833.             }
  1834.         }
  1835.     }
  1836. }
  1837.  
  1838.     /* RecurseMono(double x,double y,WORD Level):
  1839.      *
  1840.      *    Cosmic flame calculation routine (monochrome).
  1841.      */
  1842.  
  1843. BOOL
  1844. RecurseMono(double x,double y,WORD Level)
  1845. {
  1846.     ULONG Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  1847.  
  1848.         // Are we to shut down?
  1849.  
  1850.     if(Signals & SIG_BREAK)
  1851.     {
  1852.         Forbid();
  1853.  
  1854.         Signal(BlankerControlProcess,SIG_HANDSHAKE);
  1855.  
  1856.         FreeSignal(CycleBit);
  1857.  
  1858.         RemTask(NULL);
  1859.     }
  1860.  
  1861.         // Return to top level?
  1862.  
  1863.     if(StopDrawing)
  1864.     {
  1865.         FlameLevel    = 0;
  1866.         StopDrawing    = FALSE;
  1867.  
  1868.         return(FALSE);
  1869.     }
  1870.  
  1871.         // Change the pattern?
  1872.  
  1873.     if(Signals & SIG_CHANGE)
  1874.     {
  1875.         FlameLevel    = 0;
  1876.         StopDrawing    = FALSE;
  1877.  
  1878.         return(FALSE);
  1879.     }
  1880.  
  1881.         // Cycle the colours?
  1882.  
  1883.     if(Signals & CycleMask)
  1884.     {
  1885.         LoadRGB32(VPort,(ULONG *)Colours);
  1886.  
  1887.         Wheel = (Wheel + 1) % MaxColour;
  1888.  
  1889.         RotatePalette();
  1890.     }
  1891.  
  1892.     if(Level >= MaxRecursionLevel)
  1893.     {
  1894.         if((FlamePoints++) > MaxFlamePoints * 100)
  1895.             return(FALSE);
  1896.         else
  1897.             MonoPlot((WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
  1898.     }
  1899.     else
  1900.     {
  1901.         double    nx,ny;
  1902.         WORD    i;
  1903.  
  1904.         for(i = 0 ; i < 2 ; i++)
  1905.         {
  1906.             nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
  1907.             ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
  1908.  
  1909.             if(i < FlameAlternateForm)
  1910.             {
  1911.                 nx = sin(nx);
  1912.                 ny = sin(ny);
  1913.             }
  1914.  
  1915.             if(!StopDrawing)
  1916.             {
  1917.                 if(!RecurseMono(nx,ny,Level + 1))
  1918.                     return(FALSE);
  1919.             }
  1920.             else
  1921.                 return(FALSE);
  1922.         }
  1923.     }
  1924.  
  1925.     return(TRUE);
  1926. }
  1927.  
  1928.     /* RecurseColour(double x,double y,WORD Level):
  1929.      *
  1930.      *    Cosmic flame calculation routine (colour).
  1931.      */
  1932.  
  1933. BOOL
  1934. RecurseColour(double x,double y,WORD Level)
  1935. {
  1936.     ULONG Signals = SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  1937.  
  1938.     if(Signals & SIG_BREAK)
  1939.     {
  1940.         Forbid();
  1941.  
  1942.         Signal(BlankerControlProcess,SIG_HANDSHAKE);
  1943.  
  1944.         FreeSignal(CycleBit);
  1945.  
  1946.         RemTask(NULL);
  1947.     }
  1948.  
  1949.     if(StopDrawing)
  1950.     {
  1951.         FlameLevel    = 0;
  1952.         StopDrawing    = FALSE;
  1953.  
  1954.         return(FALSE);
  1955.     }
  1956.  
  1957.         /* Change the pattern? */
  1958.  
  1959.     if(Signals & SIG_CHANGE)
  1960.     {
  1961.         FlameLevel    = 0;
  1962.         StopDrawing    = FALSE;
  1963.  
  1964.         return(FALSE);
  1965.     }
  1966.  
  1967.         // Cycle the colours?
  1968.  
  1969.     if(Signals & CycleMask)
  1970.     {
  1971.         LoadRGB32(VPort,(ULONG *)Colours);
  1972.  
  1973.         Wheel = (Wheel + 1) % MaxColour;
  1974.  
  1975.         RotatePalette();
  1976.     }
  1977.  
  1978.     if(Level >= MaxRecursionLevel)
  1979.     {
  1980.         if((FlamePoints++) > MaxFlamePoints * 100)
  1981.             return(FALSE);
  1982.         else
  1983.             MultiPlot(FlameColour,(WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
  1984.     }
  1985.     else
  1986.     {
  1987.         double    nx,ny;
  1988.         WORD    i;
  1989.  
  1990.         for(i = 0 ; i < 2 ; i++)
  1991.         {
  1992.             nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
  1993.             ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
  1994.  
  1995.             if(i < FlameAlternateForm)
  1996.             {
  1997.                 nx = sin(nx);
  1998.                 ny = sin(ny);
  1999.             }
  2000.  
  2001.             if(!StopDrawing)
  2002.             {
  2003.                 if(!RecurseColour(nx,ny,Level + 1))
  2004.                     return(FALSE);
  2005.             }
  2006.             else
  2007.                 return(FALSE);
  2008.         }
  2009.     }
  2010.  
  2011.     return(TRUE);
  2012. }
  2013.  
  2014.     /* CosmicFlame():
  2015.      *
  2016.      *    The cosmic flame screen blanker.
  2017.      *
  2018.      *    xlock.c - X11 client to lock a display and show a screen saver.
  2019.      *
  2020.      *    Copyright (c) 1988-91 by Patrick J. Naughton.
  2021.      *
  2022.      *    Permission to use, copy, modify, and distribute this software and its
  2023.      *    documentation for any purpose and without fee is hereby granted,
  2024.      *    provided that the above copyright notice appear in all copies and that
  2025.      *    both that copyright notice and this permission notice appear in
  2026.      *    supporting documentation.
  2027.      */
  2028.  
  2029. VOID
  2030. CosmicFlame()
  2031. {
  2032.     WORD i,j,k;
  2033.     BOOL Alternate = FALSE;
  2034.  
  2035.     FlameLevel = 0;
  2036.  
  2037.         // Monochrome mode?
  2038.  
  2039.     if(DisplayDepth == 1)
  2040.     {
  2041.             // Go into fractal generation loop
  2042.  
  2043.         FOREVER
  2044.         {
  2045.             if(!((FlameLevel++) % MaxRecursionLevel))
  2046.             {
  2047.                 BlackScreen();
  2048.  
  2049.                 Alternate = !Alternate;
  2050.             }
  2051.  
  2052.             if(Alternate)
  2053.                 FlameAlternateForm = 0;
  2054.             else
  2055.                 FlameAlternateForm = Random(2) + 2;
  2056.  
  2057.             for(k = 0 ; k < 2 ; k++)
  2058.             {
  2059.                 for(i = 0 ; i < 2 ; i++)
  2060.                 {
  2061.                     for(j = 0; j < 3; j++)
  2062.                         Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
  2063.                 }
  2064.             }
  2065.  
  2066.             FlamePoints = 0;
  2067.  
  2068.             RecurseMono(0.0,0.0,0);
  2069.         }
  2070.     }
  2071.     else
  2072.     {
  2073.         FlameColour = Random(MaxColour - 1) + 1;
  2074.  
  2075.         FOREVER
  2076.         {
  2077.             if(!((FlameLevel++) % MaxRecursionLevel))
  2078.             {
  2079.                 BlackScreen();
  2080.  
  2081.                 Alternate = !Alternate;
  2082.             }
  2083.             else
  2084.             {
  2085.                 WORD NewColour;
  2086.  
  2087.                 do
  2088.                     NewColour = Random(MaxColour - 1) + 1;
  2089.                 while(NewColour == FlameColour);
  2090.  
  2091.                 FlameColour = NewColour;
  2092.             }
  2093.  
  2094.             if(Alternate)
  2095.                 FlameAlternateForm = 0;
  2096.             else
  2097.                 FlameAlternateForm = Random(2) + 2;
  2098.  
  2099.             for(k = 0 ; k < 2 ; k++)
  2100.             {
  2101.                 for(i = 0 ; i < 2 ; i++)
  2102.                 {
  2103.                     for(j = 0; j < 3; j++)
  2104.                         Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
  2105.                 }
  2106.             }
  2107.  
  2108.             FlamePoints = 0;
  2109.  
  2110.             RecurseColour(0.0,0.0,0);
  2111.         }
  2112.     }
  2113. }
  2114.  
  2115.     /* BlankerEntry():
  2116.      *
  2117.      *    The screen blanker itself.
  2118.      */
  2119.  
  2120. VOID __saveds
  2121. BlankerEntry()
  2122. {
  2123.     LONG CycleBit;
  2124.  
  2125.     Forbid();
  2126.  
  2127.         // Shouldn't go wrong right now, this is the second
  2128.         // action this task takes, about 16 signal bits
  2129.         // should still be vacant
  2130.  
  2131.     if((CycleBit = AllocSignal(-1)) != -1)
  2132.     {
  2133.         CycleMask = (1L << CycleBit);
  2134.  
  2135.             // Tell the control process we're running
  2136.  
  2137.         Signal(BlankerControlProcess,SIG_HANDSHAKE);
  2138.  
  2139.             // Now step back
  2140.  
  2141.         SetTaskPri(SysBase -> ThisTask,-20);
  2142.  
  2143.         Permit();
  2144.  
  2145.             // Determine the fractal type
  2146.  
  2147.         if(FractalType == FRACTAL_COSMIC_FLAME)
  2148.             CosmicFlame();
  2149.         else
  2150.         {
  2151.             if(FractalType == FRACTAL_REAL_PLANE)
  2152.                 RealPlane();
  2153.             else
  2154.             {
  2155.                 if(Random(42) >= 21)
  2156.                     CosmicFlame();
  2157.                 else
  2158.                     RealPlane();
  2159.             }
  2160.         }
  2161.     }
  2162.     else
  2163.     {
  2164.             // Wave goodbye
  2165.  
  2166.         BlankTask = NULL;
  2167.  
  2168.         Signal(BlankerControlProcess,SIG_HANDSHAKE);
  2169.     }
  2170. }
  2171.  
  2172.     /* BlankerAction(CxMsg *CxMessage,CxObj *CxObject):
  2173.      *
  2174.      *    Commodities support routine, handles the Commodities
  2175.      *    custom actions (in this case: filter the InputEvents
  2176.      *    coming in and enable/disable the screen blanker).
  2177.      */
  2178.  
  2179. VOID __saveds __stdargs
  2180. BlankerAction(CxMsg *CxMessage,CxObj *CxObject)
  2181. {
  2182.     STATIC BYTE Count = 0;
  2183.  
  2184.     struct InputEvent *Event = (struct InputEvent *)CxMsgData(CxMessage);
  2185.  
  2186.         // Push the blanker screen to the front if necessary
  2187.  
  2188.     ObtainSemaphoreShared(&BlankSemaphore);
  2189.  
  2190.     if(BlankScreen)
  2191.         Signal(BlankerControlProcess,SIG_REFRESH);
  2192.  
  2193.     ReleaseSemaphore(&BlankSemaphore);
  2194.  
  2195.         // This looks like a timer event
  2196.  
  2197.     if(Event -> ie_Class == IECLASS_TIMER)
  2198.     {
  2199.         if(!Window)
  2200.         {
  2201.                 // Screen blanker still inactive?
  2202.  
  2203.             ObtainSemaphoreShared(&BlankSemaphore);
  2204.  
  2205.             if(!BlankTask)
  2206.             {
  2207.                     // Is there a timeout to take care of?
  2208.  
  2209.                 if(ScreenTimeout && !Window)
  2210.                 {
  2211.                         // Are we ready to create the
  2212.                         // screenblanker?
  2213.  
  2214.                     if(ScreenCount++ >= ScreenTimeout * 10)
  2215.                         Signal(BlankerControlProcess,SIG_START);
  2216.                 }
  2217.             }
  2218.             else
  2219.             {
  2220.                     // Every 5/10 second we signal the blanker
  2221.                     // task to rotate the palette.
  2222.  
  2223.                 if(ColourMode == COLOUR_CYCLE)
  2224.                 {
  2225.                     if(Count++ >= 2)
  2226.                     {
  2227.                         Signal(BlankTask,CycleMask);
  2228.  
  2229.                         Count = 0;
  2230.                     }
  2231.                 }
  2232.  
  2233.                     // Is it time to change the pattern?
  2234.  
  2235.                 if(PatternTimeout)
  2236.                 {
  2237.                     if(PatternCount++ >= PatternTimeout * 10)
  2238.                     {
  2239.                         Signal(BlankerControlProcess,SIG_CHANGE);
  2240.  
  2241.                         PatternCount = 0;
  2242.                     }
  2243.                 }
  2244.             }
  2245.  
  2246.             ReleaseSemaphore(&BlankSemaphore);
  2247.         }
  2248.     }
  2249.     else
  2250.     {
  2251.             // The following lines determine whether
  2252.             // the blanker is to be removed or to
  2253.             // be left running.
  2254.  
  2255.         switch(Event -> ie_Class)
  2256.         {
  2257.             case IECLASS_RAWKEY:
  2258.  
  2259.                 if(!(Event -> ie_Code & IECODE_UP_PREFIX) && !(Event -> ie_Qualifier & SpecialQualifier))
  2260.                     Signal(BlankerControlProcess,SIG_BREAK);
  2261.  
  2262.                 break;
  2263.  
  2264.             case IECLASS_NEWPOINTERPOS:
  2265.             case IECLASS_POINTERPOS:
  2266.             case IECLASS_RAWMOUSE:
  2267.  
  2268.                 Signal(BlankerControlProcess,SIG_BREAK);
  2269.  
  2270.                 break;
  2271.         }
  2272.  
  2273.         ScreenCount = 0;
  2274.     }
  2275. }
  2276.  
  2277.     /* ShutdownCx():
  2278.      *
  2279.      *    Close the Commodities interface.
  2280.      */
  2281.  
  2282. VOID
  2283. ShutdownCx()
  2284. {
  2285.     if(CxPort)
  2286.     {
  2287.         struct Message *Message;
  2288.  
  2289.             // Remove the broker
  2290.  
  2291.         if(Broker)
  2292.             DeleteCxObjAll(Broker);
  2293.  
  2294.             // Remove the MsgPort from the public list
  2295.  
  2296.         RemPort(CxPort);
  2297.  
  2298.             // Remove all pending messages
  2299.  
  2300.         while(Message = GetMsg(CxPort))
  2301.             ReplyMsg(Message);
  2302.  
  2303.             // Delete the MsgPort
  2304.  
  2305.         DeleteMsgPort(CxPort);
  2306.  
  2307.         CxPort = NULL;
  2308.         Broker = NULL;
  2309.     }
  2310. }
  2311.  
  2312.     /* GetSeconds(STRPTR String):
  2313.      *
  2314.      *    Calculates the number of seconds corresponding to
  2315.      *    expressions such as `11:25' or `10'.
  2316.      */
  2317.  
  2318. WORD
  2319. GetSeconds(STRPTR String)
  2320. {
  2321.     UBYTE    Buffer[10];
  2322.     WORD    i,Seconds;
  2323.  
  2324.     CopyMem(String,Buffer,9);
  2325.  
  2326.     Buffer[9] = 0;
  2327.  
  2328.     String = Buffer;
  2329.  
  2330.     for(i = strlen(String) - 1 ; i >= 0 ; i--)
  2331.     {
  2332.         if(String[i] == ':')
  2333.         {
  2334.             Seconds = Atol(&String[i + 1]);
  2335.  
  2336.             String[i] = 0;
  2337.  
  2338.             Seconds += 60 * Atol(String);
  2339.  
  2340.             if(Seconds > 30 * 60)
  2341.                 Seconds = 30 * 60;
  2342.  
  2343.             return(Seconds);
  2344.         }
  2345.     }
  2346.  
  2347.     if((Seconds = Atol(String)) > 30 * 60)
  2348.         Seconds = 30 * 60;
  2349.  
  2350.     return(Seconds);
  2351. }
  2352.  
  2353.     /* SetupCx():
  2354.      *
  2355.      *    Set up the Commodities interface.
  2356.      */
  2357.  
  2358. LONG
  2359. SetupCx()
  2360. {
  2361.     LONG Error;
  2362.  
  2363.         // Cancel any previously made assignments
  2364.  
  2365.     ShutdownCx();
  2366.  
  2367.         // Create a reply port
  2368.  
  2369.     if(CxPort = CreateMsgPort())
  2370.     {
  2371.             // Fill in a unique name
  2372.  
  2373.         CxPort -> mp_Node . ln_Name = NewBroker . nb_Name;
  2374.  
  2375.             // Add the reply port to the public list
  2376.  
  2377.         AddPort(CxPort);
  2378.  
  2379.             // Install the replyport
  2380.  
  2381.         NewBroker . nb_Port = CxPort;
  2382.  
  2383.             // Create the broker
  2384.  
  2385.         if(Broker = CxBroker(&NewBroker,&Error))
  2386.         {
  2387.             CxObj *ObjectList;
  2388.  
  2389.                 // Link the hotkeys
  2390.  
  2391.             AttachCxObj(Broker,CustomHotKey(HotkeyBuffer,        CxPort,POP_WINDOW));
  2392.             AttachCxObj(Broker,CustomHotKey(BlankScreenBuffer,    CxPort,BLANK_SCREEN));
  2393.             AttachCxObj(Broker,CustomHotKey(SaveScreenBuffer,    CxPort,SAVE_SCREEN));
  2394.  
  2395.                 // Install the plain InputEvent handler
  2396.  
  2397.             ObjectList = CxCustom(BlankerAction,NULL);
  2398.  
  2399.                 // Any accumulated errors?
  2400.  
  2401.             if(!(Error = CxObjError(ObjectList)))
  2402.             {
  2403.                     // Add the custom object
  2404.  
  2405.                 AttachCxObj(Broker,ObjectList);
  2406.  
  2407.                     // Any errors?
  2408.  
  2409.                 if(!(Error = CxObjError(Broker)))
  2410.                 {
  2411.                         // Activate the broker
  2412.  
  2413.                     ActivateCxObj(Broker,TRUE);
  2414.  
  2415.                     return(0);
  2416.                 }
  2417.             }
  2418.  
  2419.             if(Error & COERR_BADFILTER)
  2420.                 Error = ERR_BadFilter;
  2421.             else
  2422.             {
  2423.                 if(Error & COERR_BADTYPE)
  2424.                     Error = ERR_BadType;
  2425.                 else
  2426.                     Error = ERROR_NO_FREE_STORE;
  2427.             }
  2428.         }
  2429.         else
  2430.             Error = Error - CBERR_SYSERR + ERR_SystemError;
  2431.     }
  2432.     else
  2433.         Error = ERR_NoMsgPort;
  2434.  
  2435.     ShutdownCx();
  2436.  
  2437.     return(Error);
  2438. }
  2439.  
  2440.     /* SaverEntry():
  2441.      *
  2442.      *    This background process handles the job of storing the
  2443.      *    contents of the screen in the clipboard.
  2444.      */
  2445.  
  2446. VOID __saveds
  2447. SaverEntry()
  2448. {
  2449.     struct BitMap *BitMap;
  2450.  
  2451.         // That's me
  2452.  
  2453.     Saver = (struct Process *)FindTask(NULL);
  2454.  
  2455.     ObtainSemaphoreShared(&BlankSemaphore);
  2456.  
  2457.     Forbid();
  2458.  
  2459.         // Create a bitmap to hold a copy of the screen
  2460.  
  2461.     if(BitMap = AllocBitMap(Width,Height,DisplayDepth,NULL,RPort -> BitMap))
  2462.     {
  2463.         STATIC ULONG Count = 1;
  2464.  
  2465.         UBYTE     LocalBuffer[256];
  2466.         Object    *Image;
  2467.  
  2468.             // Copy the contents
  2469.  
  2470.         BltBitMap(RPort -> BitMap,0,0,BitMap,0,0,Width,Height,0xC0,(1L << DisplayDepth) - 1,NULL);
  2471.  
  2472.             // Wait until they have arrived
  2473.  
  2474.         WaitBlit();
  2475.  
  2476.         Permit();
  2477.  
  2478.         ReleaseSemaphore(&BlankSemaphore);
  2479.  
  2480.             // Build a unique name, in case someone needs it
  2481.  
  2482.         SPrintf(LocalBuffer,"FracBlank_%ld×%ld×%ld_%ld",Width,Height,DisplayDepth,Count++);
  2483.  
  2484.             // Wrap the bitmap into an image object
  2485.  
  2486.         if(Image = NewDTObject(LocalBuffer,
  2487.             DTA_SourceType,    DTST_RAM,
  2488.             DTA_GroupID,    GID_PICTURE,
  2489.             PDTA_NumColors,    1L << DisplayDepth,
  2490.             PDTA_BitMap,    BitMap,
  2491.             PDTA_ModeID,    GetVPModeID(&BlankScreen -> ViewPort),
  2492.         TAG_DONE))
  2493.         {
  2494.             struct ColorRegister    *ColourMap;
  2495.             struct BitMapHeader    *BitMapHeader;
  2496.             ULONG            *ColourTab;
  2497.  
  2498.                 // Get the internal data storage pointers
  2499.  
  2500.             if(GetDTAttrs(Image,
  2501.                 PDTA_BitMapHeader,    &BitMapHeader,
  2502.                 PDTA_ColorRegisters,    &ColourMap,
  2503.                 PDTA_CRegs,        &ColourTab,
  2504.             TAG_DONE) == 3)
  2505.             {
  2506.                 LONG i;
  2507.  
  2508.                     // Fill in the header
  2509.  
  2510.                 BitMapHeader -> bmh_Left    = 0;
  2511.                 BitMapHeader -> bmh_Top        = 0;
  2512.                 BitMapHeader -> bmh_Width    = Width;
  2513.                 BitMapHeader -> bmh_Height    = Height;
  2514.                 BitMapHeader -> bmh_Depth    = DisplayDepth;
  2515.                 BitMapHeader -> bmh_PageWidth    = Width;
  2516.                 BitMapHeader -> bmh_PageHeight    = Height;
  2517.  
  2518.                     // Fill in the colour tables
  2519.  
  2520.                 for(i = 0 ; i < 1L << DisplayDepth ; i++)
  2521.                 {
  2522.                     ColourTab[i * 3 + 0]    = Colours -> Entry[i] . Red;
  2523.                     ColourTab[i * 3 + 1]    = Colours -> Entry[i] . Green;
  2524.                     ColourTab[i * 3 + 2]    = Colours -> Entry[i] . Blue;
  2525.  
  2526.                     ColourMap[i] . red    = Colours -> Entry[i] . Red    >> 24;
  2527.                     ColourMap[i] . green    = Colours -> Entry[i] . Green    >> 24;
  2528.                     ColourMap[i] . blue    = Colours -> Entry[i] . Blue    >> 24;
  2529.                 }
  2530.  
  2531.                     // Put the image into the clipboard
  2532.  
  2533.                 DoMethod(Image,DTM_COPY,NULL);
  2534.             }
  2535.  
  2536.             DisposeDTObject(Image);
  2537.         }
  2538.         else
  2539.             FreeBitMap(BitMap);
  2540.     }
  2541.     else
  2542.     {
  2543.         Permit();
  2544.  
  2545.         ReleaseSemaphore(&BlankSemaphore);
  2546.     }
  2547.  
  2548.     Forbid();
  2549.  
  2550.     Saver = NULL;
  2551. }
  2552.  
  2553.     /* HandleCxMsg(CxMsg *Message):
  2554.      *
  2555.      *    Handle incoming Commodities messages.
  2556.      */
  2557.  
  2558. VOID
  2559. HandleCxMsg(CxMsg *Message)
  2560. {
  2561.     ULONG MessageID = CxMsgID(Message),MessageType = CxMsgType(Message);
  2562.  
  2563.     ReplyMsg((struct Message *)Message);
  2564.  
  2565.         // Take a look at the message type
  2566.  
  2567.     switch(MessageType)
  2568.     {
  2569.             // It's a hotkey
  2570.  
  2571.         case CXM_IEVENT:
  2572.  
  2573.             switch(MessageID)
  2574.             {
  2575.                     // Create the control panel
  2576.  
  2577.                 case POP_WINDOW:
  2578.  
  2579.                         // Make sure the blanker has terminated
  2580.  
  2581.                     Signal(BlankerControlProcess,SIG_BREAK);
  2582.  
  2583.                     SetupWindow();
  2584.  
  2585.                     break;
  2586.  
  2587.                     // Blank the screen
  2588.  
  2589.                 case BLANK_SCREEN:
  2590.  
  2591.                     if(!Window)
  2592.                     {
  2593.                         ObtainSemaphoreShared(&BlankSemaphore);
  2594.  
  2595.                         if(!BlankTask)
  2596.                             Signal(BlankerControlProcess,SIG_START);
  2597.                         else
  2598.                         {
  2599.                             Signal(BlankerControlProcess,SIG_CHANGE);
  2600.  
  2601.                             PatternCount = 0;
  2602.                         }
  2603.  
  2604.                         ReleaseSemaphore(&BlankSemaphore);
  2605.                     }
  2606.  
  2607.                     break;
  2608.  
  2609.                     // Save the screen in the clipboard
  2610.  
  2611.                 case SAVE_SCREEN:
  2612.  
  2613.                     if(DataTypesBase)
  2614.                     {
  2615.                         ObtainSemaphoreShared(&BlankSemaphore);
  2616.  
  2617.                             // Let the background process handle the job
  2618.  
  2619.                         if(BlankScreen && !Saver)
  2620.                         {
  2621.                             CreateNewProcTags(
  2622.                                 NP_Name,    "« FracBlank Screen Saver »",
  2623.                                 NP_Entry,    SaverEntry,
  2624.                                 NP_StackSize,    4096,
  2625.                                 NP_WindowPtr,    -1,
  2626.                             TAG_DONE);
  2627.                         }
  2628.  
  2629.                         ReleaseSemaphore(&BlankSemaphore);
  2630.                     }
  2631.  
  2632.                     break;
  2633.             }
  2634.  
  2635.             break;
  2636.  
  2637.             // It's an internal Commodities command
  2638.  
  2639.         case CXM_COMMAND:
  2640.  
  2641.             switch(MessageID)
  2642.             {
  2643.                     // Disable the Commodity
  2644.  
  2645.                 case CXCMD_DISABLE:
  2646.  
  2647.                     ActivateCxObj(Broker,FALSE);
  2648.                     break;
  2649.  
  2650.                     // Enable the Commodity
  2651.  
  2652.                 case CXCMD_ENABLE:
  2653.  
  2654.                     ActivateCxObj(Broker,TRUE);
  2655.                     break;
  2656.  
  2657.                     // Create the control panel
  2658.  
  2659.                 case CXCMD_APPEAR:
  2660.                 case CXCMD_UNIQUE:
  2661.  
  2662.                     SetupWindow();
  2663.                     break;
  2664.  
  2665.                     // Close the control panel
  2666.  
  2667.                 case CXCMD_DISAPPEAR:
  2668.  
  2669.                     ShutdownWindow();
  2670.                     break;
  2671.  
  2672.                     // Remove this Commodity
  2673.  
  2674.                 case CXCMD_KILL:
  2675.  
  2676.                     CloseAll(RETURN_OK);
  2677.                     break;
  2678.             }
  2679.  
  2680.             break;
  2681.     }
  2682. }
  2683.  
  2684.     /* ShowTime(struct Gadget *SomeGadget,WORD Level):
  2685.      *
  2686.      *    Gadtools support routine, displays the timeouts.
  2687.      */
  2688.  
  2689. LONG __saveds __stdargs
  2690. ShowTime(struct Gadget *SomeGadget,WORD Level)
  2691. {
  2692.     STATIC UBYTE Buffer[30];
  2693.  
  2694.     if(Level)
  2695.         SPrintf(Buffer,"%2ld:%02ld min.",Level / 60,Level % 60);
  2696.     else
  2697.         SPrintf(Buffer,"«Off»");
  2698.  
  2699.     return((LONG)Buffer);
  2700. }
  2701.  
  2702.     /* ShowDots(struct Gadget *SomeGadget,WORD Level):
  2703.      *
  2704.      *    Cheap trick; multiply the number of dots by 100.
  2705.      */
  2706.  
  2707. LONG __saveds __stdargs
  2708. ShowDots(struct Gadget *SomeGadget,WORD Level)
  2709. {
  2710.     return((LONG)Level * 100);
  2711. }
  2712.  
  2713.     /* ShutdownWindow():
  2714.      *
  2715.      *    Closes the control panel.
  2716.      */
  2717.  
  2718. VOID
  2719. ShutdownWindow()
  2720. {
  2721.     if(Handle)
  2722.     {
  2723.         LT_DeleteHandle(Handle);
  2724.  
  2725.         Handle = NULL;
  2726.  
  2727.         Window = NULL;
  2728.  
  2729.         CloseLibrary(GTLayoutBase);
  2730.  
  2731.         GTLayoutBase = NULL;
  2732.     }
  2733. }
  2734.  
  2735.     /* SetupWindow():
  2736.      *
  2737.      *    Creates the control panel and disables the screen
  2738.      *    blanker.
  2739.      */
  2740.  
  2741. BOOL
  2742. SetupWindow()
  2743. {
  2744.     if(Handle)
  2745.     {
  2746.         LT_ShowWindow(Handle,TRUE);
  2747.  
  2748.         return(TRUE);
  2749.     }
  2750.     else
  2751.     {
  2752.         if(!(GTLayoutBase = SafeOpenLibrary("PROGDIR:gtlayout.library",9)))
  2753.             GTLayoutBase = SafeOpenLibrary("gtlayout.library",9);
  2754.  
  2755.         if(GTLayoutBase)
  2756.         {
  2757.             if(Handle = LT_CreateHandleTagList(NULL,NULL))
  2758.             {
  2759.                 LT_New(Handle,
  2760.                     LA_Type,    VERTICAL_KIND,
  2761.                 TAG_DONE);
  2762.                 {
  2763.                     LT_New(Handle,
  2764.                         LA_LabelText,    "Fractal screen blanker",
  2765.                         LA_Type,    VERTICAL_KIND,
  2766.                     TAG_DONE);
  2767.                     {
  2768.                         STATIC STRPTR Copyright[] =
  2769.                         {
  2770.                             "Copyright © 1991-1995",
  2771.                             "by Olaf `Olsen' Barthel",
  2772.                             "All Rights Reserved",
  2773.                             NULL
  2774.                         };
  2775.  
  2776.                         LT_New(Handle,
  2777.                             LA_Type,    BOX_KIND,
  2778.                             LABX_Lines,    Copyright,
  2779.                             LABX_AlignText,    ALIGNTEXT_CENTERED,
  2780.                             LA_DrawBox,    FALSE,
  2781.                         TAG_DONE);
  2782.  
  2783.                         LT_EndGroup(Handle);
  2784.                     }
  2785.  
  2786.                     LT_New(Handle,
  2787.                         LA_LabelText,    "Controls",
  2788.                         LA_Type,    VERTICAL_KIND,
  2789.                     TAG_DONE);
  2790.                     {
  2791.                         STATIC STRPTR FractalTypes[] =
  2792.                         {
  2793.                             "Real plane",
  2794.                             "Cosmic flames",
  2795.                             "« Random »",
  2796.                             NULL
  2797.                         };
  2798.  
  2799.                         STATIC STRPTR ColourModes[] =
  2800.                         {
  2801.                             "Cycling",
  2802.                             "Static",
  2803.                             NULL
  2804.                         };
  2805.  
  2806.                         LT_New(Handle,
  2807.                             LA_Type,        SLIDER_KIND,
  2808.                             LA_LabelText,        "Screen timeout",
  2809.                             GTSL_Min,        0,
  2810.                             GTSL_Max,        30 * 60,
  2811.                             GTSL_LevelFormat,    "%s",
  2812.                             GTSL_DispFunc,        ShowTime,
  2813.                             LA_ULONG,        &ScreenTimeout,
  2814.                             LA_Chars,        20,
  2815.                         TAG_DONE);
  2816.  
  2817.                         LT_New(Handle,
  2818.                             LA_Type,        SLIDER_KIND,
  2819.                             LA_LabelText,        "Pattern timeout",
  2820.                             GTSL_Min,        0,
  2821.                             GTSL_Max,        30 * 60,
  2822.                             GTSL_LevelFormat,    "%s",
  2823.                             GTSL_DispFunc,        ShowTime,
  2824.                             LA_ULONG,        &PatternTimeout,
  2825.                         TAG_DONE);
  2826.  
  2827.                         LT_New(Handle,
  2828.                             LA_Type,        XBAR_KIND,
  2829.                         TAG_DONE);
  2830.  
  2831.                         EditHook . h_Entry = (HOOKFUNC)EditRoutine;
  2832.  
  2833.                         LT_New(Handle,
  2834.                             LA_Type,        STRING_KIND,
  2835.                             LA_LabelText,        "Hot key",
  2836.                             GTST_MaxChars,        255,
  2837.                             GTST_String,        HotkeyBuffer,
  2838.                             GTST_EditHook,        &EditHook,
  2839.                             LA_ID,            GAD_HOTKEY,
  2840.                         TAG_DONE);
  2841.  
  2842.                         LT_New(Handle,
  2843.                             LA_Type,        STRING_KIND,
  2844.                             LA_LabelText,        "Blank screen",
  2845.                             GTST_MaxChars,        255,
  2846.                             GTST_String,        BlankScreenBuffer,
  2847.                             GTST_EditHook,        &EditHook,
  2848.                             LA_ID,            GAD_BLANKSCREEN,
  2849.                         TAG_DONE);
  2850.  
  2851.                         if(DataTypesBase)
  2852.                         {
  2853.                             LT_New(Handle,
  2854.                                 LA_Type,    STRING_KIND,
  2855.                                 LA_LabelText,    "Save screen to clipboard",
  2856.                                 GTST_MaxChars,    255,
  2857.                                 GTST_String,    SaveScreenBuffer,
  2858.                                 GTST_EditHook,    &EditHook,
  2859.                                 LA_ID,        GAD_SAVESCREEN,
  2860.                             TAG_DONE);
  2861.                         }
  2862.  
  2863.                         LT_New(Handle,
  2864.                             LA_Type,        XBAR_KIND,
  2865.                         TAG_DONE);
  2866.  
  2867.                         UpdateModeString();
  2868.  
  2869.                         LT_New(Handle,
  2870.                             LA_Type,        TEXT_KIND,
  2871.                             LA_LabelText,        "Display mode",
  2872.                             LA_ID,            GAD_MODE,
  2873.                             GTTX_Text,        DisplayModeBuffer,
  2874.                             GTTX_Border,        TRUE,
  2875.                             LATX_Picker,        TRUE,
  2876.                         TAG_DONE);
  2877.  
  2878.                         LT_New(Handle,
  2879.                             LA_Type,        XBAR_KIND,
  2880.                         TAG_DONE);
  2881.  
  2882.                         LT_New(Handle,
  2883.                             LA_Type,        CYCLE_KIND,
  2884.                             LA_LabelText,        "Colour mode",
  2885.                             GTCY_Labels,        ColourModes,
  2886.                             LA_UBYTE,        &ColourMode,
  2887.                         TAG_DONE);
  2888.  
  2889.                         LT_New(Handle,
  2890.                             LA_Type,        CYCLE_KIND,
  2891.                             LA_LabelText,        "Fractal type",
  2892.                             GTCY_Labels,        FractalTypes,
  2893.                             LA_UBYTE,        &FractalType,
  2894.                         TAG_DONE);
  2895.  
  2896.                         LT_New(Handle,
  2897.                             LA_Type,        SLIDER_KIND,
  2898.                             LA_LabelText,        "Maximum recursion level",
  2899.                             GTSL_Min,        10,
  2900.                             GTSL_Max,        100,
  2901.                             GTSL_LevelFormat,    "%ld",
  2902.                             LA_ULONG,        &MaxRecursionLevel,
  2903.                         TAG_DONE);
  2904.  
  2905.                         LT_New(Handle,
  2906.                             LA_Type,        SLIDER_KIND,
  2907.                             LA_LabelText,        "Maximum dots",
  2908.                             GTSL_Min,        10,
  2909.                             GTSL_Max,        1000,
  2910.                             GTSL_LevelFormat,    "%lD",
  2911.                             GTSL_DispFunc,        ShowDots,
  2912.                             LA_ULONG,        &MaxFlamePoints,
  2913.                         TAG_DONE);
  2914.  
  2915.                         LT_EndGroup(Handle);
  2916.                     }
  2917.  
  2918.                     LT_New(Handle,
  2919.                         LA_Type,    VERTICAL_KIND,
  2920.                     TAG_DONE);
  2921.                     {
  2922.                         LT_New(Handle,
  2923.                             LA_Type,        XBAR_KIND,
  2924.                             LAXB_FullSize,        TRUE,
  2925.                         TAG_DONE);
  2926.  
  2927.                         LT_EndGroup(Handle);
  2928.                     }
  2929.  
  2930.                     LT_New(Handle,
  2931.                         LA_Type,    HORIZONTAL_KIND,
  2932.                         LAGR_Spread,    TRUE,
  2933.                         LAGR_SameSize,    TRUE,
  2934.                     TAG_DONE);
  2935.                     {
  2936.                         if(!MainProcess -> pr_CLI)
  2937.                         {
  2938.                             LT_New(Handle,
  2939.                                 LA_Type,    BUTTON_KIND,
  2940.                                 LA_LabelText,    "Save",
  2941.                                 LABT_ExtraFat,    TRUE,
  2942.                                 LA_ID,        GAD_SAVE,
  2943.                                 LA_Chars,    8,
  2944.                             TAG_DONE);
  2945.                         }
  2946.  
  2947.                         LT_New(Handle,
  2948.                             LA_Type,    BUTTON_KIND,
  2949.                             LA_LabelText,    "Hide",
  2950.                             LABT_ReturnKey,    TRUE,
  2951.                             LABT_ExtraFat,    TRUE,
  2952.                             LA_ID,        GAD_HIDE,
  2953.                             LA_Chars,    8,
  2954.                         TAG_DONE);
  2955.  
  2956.                         LT_New(Handle,
  2957.                             LA_Type,    BUTTON_KIND,
  2958.                             LA_LabelText,    "Quit",
  2959.                             LA_ID,        GAD_QUIT,
  2960.                         TAG_DONE);
  2961.  
  2962.                         LT_EndGroup(Handle);
  2963.                     }
  2964.  
  2965.                     LT_EndGroup(Handle);
  2966.                 }
  2967.  
  2968.                 if(Window = LT_Build(Handle,
  2969.                     LAWN_IDCMP,        IDCMP_CLOSEWINDOW,
  2970.                     LAWN_BelowMouse,    TRUE,
  2971.                     LAWN_SmartZoom,        TRUE,
  2972.                     LAWN_TitleText,        &VersTag[7],
  2973.                     WA_DepthGadget,        TRUE,
  2974.                     WA_CloseGadget,        TRUE,
  2975.                     WA_DragBar,        TRUE,
  2976.                     WA_RMBTrap,        TRUE,
  2977.                     WA_Activate,        TRUE,
  2978.                 TAG_DONE))
  2979.                 {
  2980.                     ResetRequest = TRUE;
  2981.  
  2982.                     return(TRUE);
  2983.                 }
  2984.  
  2985.                 LT_DeleteHandle(Handle);
  2986.  
  2987.                 Handle = NULL;
  2988.             }
  2989.  
  2990.             ReportError(NULL,NULL,ERR_NoWindow);
  2991.  
  2992.             CloseLibrary(GTLayoutBase);
  2993.  
  2994.             GTLayoutBase = NULL;
  2995.         }
  2996.         else
  2997.             ReportError(NULL,NULL,ERR_NoGTLayout);
  2998.  
  2999.         return(FALSE);
  3000.     }
  3001. }
  3002.  
  3003.     /* CloseAll(LONG ReturnCode):
  3004.      *
  3005.      *    Free all resources and exit the program.
  3006.      */
  3007.  
  3008. VOID
  3009. CloseAll(LONG ReturnCode)
  3010. {
  3011.         // Wait until the screen is saved
  3012.  
  3013.     while(Saver)
  3014.         Delay(TICKS_PER_SECOND);
  3015.  
  3016.     if(CxBase)
  3017.         ShutdownCx();
  3018.  
  3019.     if(BlankerControlProcess)
  3020.     {
  3021.         Forbid();
  3022.  
  3023.         SetSignal(0,SIG_HANDSHAKE);
  3024.  
  3025.         Signal(BlankerControlProcess,SIG_FINISH);
  3026.  
  3027.         Wait(SIG_HANDSHAKE);
  3028.  
  3029.         Permit();
  3030.     }
  3031.  
  3032.     if(Pointer)
  3033.         DisposeObject(Pointer);
  3034.  
  3035.     ShutdownWindow();
  3036.  
  3037.     if(Colours)
  3038.         FreeVec(Colours);
  3039.  
  3040.     if(ScreenModeRequest)
  3041.         FreeAslRequest(ScreenModeRequest);
  3042.  
  3043.     if(KeymapBase)
  3044.         CloseLibrary(KeymapBase);
  3045.  
  3046.     if(IconBase)
  3047.         CloseLibrary(IconBase);
  3048.  
  3049.     if(UtilityBase)
  3050.         CloseLibrary(UtilityBase);
  3051.  
  3052.     if(CxBase)
  3053.         CloseLibrary(CxBase);
  3054.  
  3055.     if(AslBase)
  3056.         CloseLibrary(AslBase);
  3057.  
  3058.     if(DataTypesBase)
  3059.         CloseLibrary(DataTypesBase);
  3060.  
  3061.     if(GfxBase)
  3062.         CloseLibrary(GfxBase);
  3063.  
  3064.     if(IntuitionBase)
  3065.         CloseLibrary(IntuitionBase);
  3066.  
  3067.     exit(ReturnCode);
  3068. }
  3069.  
  3070.     /* OpenAll(int argc,char **argv):
  3071.      *
  3072.      *    Open all resources, initialize the colour table and
  3073.      *    create the Commodities interface.
  3074.      */
  3075.  
  3076. VOID
  3077. OpenAll(int argc,char **argv)
  3078. {
  3079.     STRPTR            *ToolTypes,
  3080.                  String,
  3081.                  Array[ARGCOUNT];
  3082.     struct RDArgs        *Args;
  3083.     struct DiskObject    *Icon;
  3084.     IX             Expression;
  3085.     LONG             Error;
  3086.  
  3087.         // Initialize this, the rotation code needs it
  3088.  
  3089.     deg45 = sin(-45.0);
  3090.  
  3091.     ScreenHook . h_Entry = (HOOKFUNC)BackfillDummy;
  3092.     WindowHook . h_Entry = (HOOKFUNC)BackfillDummy;
  3093.  
  3094.     InitSemaphore(&BlankSemaphore);
  3095.  
  3096.     MainProcess = (struct Process *)FindTask(NULL);
  3097.  
  3098.         // Open the libraries we need
  3099.  
  3100.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  3101.         CloseAll(RETURN_FAIL);
  3102.  
  3103.     if(!(CxBase = OpenLibrary("commodities.library",37)))
  3104.     {
  3105.         ReportError(NULL,NULL,ERR_NoCommodities);
  3106.  
  3107.         CloseAll(RETURN_FAIL);
  3108.     }
  3109.  
  3110.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  3111.     {
  3112.         ReportError(NULL,NULL,ERR_NoUtility);
  3113.  
  3114.         CloseAll(RETURN_FAIL);
  3115.     }
  3116.  
  3117.     if(!(IconBase = OpenLibrary("icon.library",0)))
  3118.     {
  3119.         ReportError(NULL,NULL,ERR_NoIcon);
  3120.  
  3121.         CloseAll(RETURN_FAIL);
  3122.     }
  3123.  
  3124.     if(!(AslBase = OpenLibrary("asl.library",38)))
  3125.     {
  3126.         ReportError(NULL,NULL,ERR_NoAsl);
  3127.  
  3128.         CloseAll(RETURN_FAIL);
  3129.     }
  3130.  
  3131.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
  3132.     {
  3133.         ReportError(NULL,NULL,ERR_NoGfx);
  3134.  
  3135.         CloseAll(RETURN_FAIL);
  3136.     }
  3137.  
  3138.     if(!(KeymapBase = OpenLibrary("keymap.library",37)))
  3139.     {
  3140.         ReportError(NULL,NULL,ERR_NoKeymap);
  3141.  
  3142.         CloseAll(RETURN_FAIL);
  3143.     }
  3144.  
  3145.     DataTypesBase = OpenLibrary("datatypes.library",39);
  3146.  
  3147.     if(!(ScreenModeRequest = AllocAslRequestTags(ASL_ScreenModeRequest,
  3148.         ASLSM_DoDepth,        TRUE,
  3149.         ASLSM_PropertyFlags,    NULL,
  3150.         ASLSM_PropertyMask,    DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE,
  3151.         ASLSM_MinDepth,        1,
  3152.         ASLSM_MaxDepth,        8,
  3153.         ASLSM_UserData,        FALSE,
  3154.     TAG_DONE)))
  3155.     {
  3156.         ReportError(NULL,NULL,ERR_ScreenModeRequest);
  3157.  
  3158.         CloseAll(RETURN_FAIL);
  3159.     }
  3160.  
  3161.         // Set up a transparent window pointer
  3162.  
  3163.     InitBitMap(&PointerBitMap,2,16,1);
  3164.  
  3165.     PointerBitMap . Planes[0] = PointerBitMap . Planes[1] = (PLANEPTR)&Nothing;
  3166.  
  3167.     if(!(Pointer = NewObject(NULL,POINTERCLASS,
  3168.         POINTERA_BitMap,    &PointerBitMap,
  3169.         POINTERA_XOffset,    0,
  3170.         POINTERA_YOffset,    0,
  3171.         POINTERA_WordWidth,    2,
  3172.     TAG_DONE)))
  3173.     {
  3174.         ReportError(NULL,NULL,ERR_NoPointer);
  3175.  
  3176.         CloseAll(RETURN_FAIL);
  3177.     }
  3178.  
  3179.     if(!(Colours = (ColourTable *)AllocVec(sizeof(ColourTable) + 255 * sizeof(ColourEntry),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  3180.     {
  3181.         ReportError(NULL,NULL,ERR_NoColours);
  3182.  
  3183.         CloseAll(RETURN_FAIL);
  3184.     }
  3185.  
  3186.     Forbid();
  3187.  
  3188.     if(BlankerControlProcess = CreateNewProcTags(
  3189.         NP_Name,    "« FracBlank Control Process »",
  3190.         NP_Priority,    100,
  3191.         NP_Entry,    BlankerControlEntry,
  3192.         NP_StackSize,    4096,
  3193.         NP_WindowPtr,    -1,
  3194.     TAG_DONE))
  3195.     {
  3196.         SetSignal(0,SIG_HANDSHAKE);
  3197.  
  3198.             // Wait for handshake signal
  3199.  
  3200.         Wait(SIG_HANDSHAKE);
  3201.     }
  3202.  
  3203.     Permit();
  3204.  
  3205.     if(!BlankerControlProcess)
  3206.     {
  3207.         ReportError(NULL,NULL,ERR_NoControlProcess);
  3208.  
  3209.         CloseAll(RETURN_FAIL);
  3210.     }
  3211.  
  3212.     memset(Array,0,sizeof(Array));
  3213.  
  3214.     if(argc)
  3215.     {
  3216.         if(!(Args = ReadArgs("CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/K,BLANKSCREEN/K,SAVESCREEN/K,FRACTAL/K,COLOUR/K,DISPLAYMODE/K,DEPTH/N/K,SCREENTIMEOUT/K,PATTERNTIMEOUT/K,MAXRECURSION/N/K,MAXDOTS/N/K",(LONG *)Array,NULL)))
  3217.         {
  3218.             PrintFault(IoErr(),"FracBlank");
  3219.  
  3220.             CloseAll(RETURN_FAIL);
  3221.         }
  3222.  
  3223.         ToolTypes    = NULL;
  3224.         Icon        = NULL;
  3225.     }
  3226.     else
  3227.     {
  3228.         struct WBStartup    *Startup = (struct WBStartup *)argv;
  3229.         BPTR             OldDir;
  3230.  
  3231.         Args = NULL;
  3232.  
  3233.         OldDir = CurrentDir(MainProcess -> pr_HomeDir);
  3234.  
  3235.         if(Icon = GetDiskObject(Startup -> sm_ArgList -> wa_Name))
  3236.             ToolTypes = (STRPTR *)Icon -> do_ToolTypes;
  3237.         else
  3238.             ToolTypes = NULL;
  3239.  
  3240.         CurrentDir(OldDir);
  3241.     }
  3242.  
  3243.     NewBroker . nb_Pri = ToolValue(ToolTypes,"CX_PRIORITY",Array[ARG_PRIORITY] ? *(LONG *)Array[ARG_PRIORITY] : 0);
  3244.  
  3245.     if(NewBroker . nb_Pri < -128)
  3246.         NewBroker . nb_Pri = -128;
  3247.     else
  3248.     {
  3249.         if(NewBroker . nb_Pri > 127)
  3250.             NewBroker . nb_Pri = 127;
  3251.     }
  3252.  
  3253.         // We'll put up a mask of qualifiers we don't want the blanker
  3254.         // to stop at
  3255.  
  3256.     SpecialQualifier = IEQUALIFIER_REPEAT;
  3257.  
  3258.         // Set the Commodity popup hotkey if possible
  3259.  
  3260.     strcpy(HotkeyBuffer,ToolString(ToolTypes,"CX_POPKEY",Array[ARG_POPKEY] ? Array[ARG_POPKEY] : (STRPTR)"shift f1"));
  3261.  
  3262.     SpecialQualifier = AddQualifier(HotkeyBuffer,SpecialQualifier);
  3263.  
  3264.     if(Error = ParseIX(HotkeyBuffer,&Expression))
  3265.     {
  3266.         ReportError(NULL,"Invalid CX_POPKEY specification\n%s",ERR_BadFilter);
  3267.  
  3268.         CloseAll(RETURN_FAIL);
  3269.     }
  3270.  
  3271.         /* Determine the screen blanker hotkey. */
  3272.  
  3273.     strcpy(BlankScreenBuffer,ToolString(ToolTypes,"BLANKSCREEN",Array[ARG_BLANKSCREEN] ? Array[ARG_BLANKSCREEN] : (STRPTR)"shift f2"));
  3274.  
  3275.     SpecialQualifier = AddQualifier(BlankScreenBuffer,SpecialQualifier);
  3276.  
  3277.     if(Error = ParseIX(BlankScreenBuffer,&Expression))
  3278.     {
  3279.         ReportError(NULL,"Invalid BLANKSCREEN specification\n%s",ERR_BadFilter);
  3280.  
  3281.         CloseAll(RETURN_FAIL);
  3282.     }
  3283.  
  3284.         // Set the screen save hotkey
  3285.  
  3286.     strcpy(SaveScreenBuffer,ToolString(ToolTypes,"SAVESCREEN",Array[ARG_SAVESCREEN] ? Array[ARG_SAVESCREEN] : (STRPTR)"shift f3"));
  3287.  
  3288.     SpecialQualifier = AddQualifier(SaveScreenBuffer,SpecialQualifier);
  3289.  
  3290.     if(Error = ParseIX(SaveScreenBuffer,&Expression))
  3291.     {
  3292.         ReportError(NULL,"Invalid SAVESCREEN specification\n%s",ERR_BadFilter);
  3293.  
  3294.         CloseAll(RETURN_FAIL);
  3295.     }
  3296.  
  3297.         // Which fractal type?
  3298.  
  3299.     String = ToolString(ToolTypes,"FRACTAL",Array[ARG_FRACTAL] ? Array[ARG_FRACTAL] : (STRPTR)"RANDOM");
  3300.  
  3301.     if(MatchToolValue(String,"REALPLANE") || MatchToolValue(String,"REAL"))
  3302.         FractalType = FRACTAL_REAL_PLANE;
  3303.     else
  3304.     {
  3305.         if(MatchToolValue(String,"COSMICFLAME") || MatchToolValue(String,"COSMIC") || MatchToolValue(String,"FLAME"))
  3306.             FractalType = FRACTAL_COSMIC_FLAME;
  3307.         else
  3308.             FractalType = FRACTAL_RANDOM;
  3309.     }
  3310.  
  3311.         // Which colour mode?
  3312.  
  3313.     String = ToolString(ToolTypes,"COLOUR",Array[ARG_COLOUR] ? Array[ARG_COLOUR] : (STRPTR)"CYCLE");
  3314.  
  3315.     if(MatchToolValue(String,"STATIC"))
  3316.         ColourMode = COLOUR_STATIC;
  3317.     else
  3318.         ColourMode = COLOUR_CYCLE;
  3319.  
  3320.         // Which display mode?
  3321.  
  3322.     DisplayID = INVALID_ID;
  3323.  
  3324.     if(String = ToolString(ToolTypes,"DISPLAYMODE",Array[ARG_DISPLAYMODE]))
  3325.     {
  3326.         UBYTE LocalBuffer[40];
  3327.         ULONG ID = INVALID_ID;
  3328.  
  3329.         while((ID = NextDisplayInfo(ID)) != INVALID_ID)
  3330.         {
  3331.             if(GetModeName(ID,LocalBuffer))
  3332.             {
  3333.                 if(!Stricmp(LocalBuffer,String))
  3334.                 {
  3335.                     struct DisplayInfo DisplayInfo;
  3336.  
  3337.                     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,ID))
  3338.                     {
  3339.                         if(!(DisplayInfo . NotAvailable & ~DI_AVAIL_NOTWITHGENLOCK))
  3340.                         {
  3341.                             if(!(DisplayInfo . PropertyFlags & (DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE)))
  3342.                             {
  3343.                                 DisplayID = ID;
  3344.  
  3345.                                 break;
  3346.                             }
  3347.                         }
  3348.                     }
  3349.                 }
  3350.             }
  3351.         }
  3352.     }
  3353.  
  3354.         // Which depth?
  3355.  
  3356.     Depth = ToolValue(ToolTypes,"DEPTH",Array[ARG_DEPTH] ? *(LONG *)Array[ARG_DEPTH] : 0);
  3357.  
  3358.     if(Depth > 8)
  3359.         Depth = 8;
  3360.     else
  3361.     {
  3362.         if(Depth < 0)
  3363.             Depth = 0;
  3364.     }
  3365.  
  3366.         // Adjust the screen timeout if possible
  3367.  
  3368.     ScreenTimeout = GetSeconds(ToolString(ToolTypes,"SCREENTIMEOUT",Array[ARG_SCREENTIMEOUT] ? Array[ARG_SCREENTIMEOUT] : (STRPTR)"1:00"));
  3369.  
  3370.         // Adjust the pattern change timeout
  3371.  
  3372.     PatternTimeout = GetSeconds(ToolString(ToolTypes,"PATTERNTIMEOUT",Array[ARG_PATTERNTIMEOUT] ? Array[ARG_PATTERNTIMEOUT] : (STRPTR)"1:00"));
  3373.  
  3374.         // Take care of the recursion level
  3375.  
  3376.     MaxRecursionLevel = ToolValue(ToolTypes,"MAXRECURSION",Array[ARG_MAXRECURSION] ? *(LONG *)Array[ARG_MAXRECURSION] : 40);
  3377.  
  3378.     if(MaxRecursionLevel < 10)
  3379.         MaxRecursionLevel = 10;
  3380.     else
  3381.     {
  3382.         if(MaxRecursionLevel > 100)
  3383.             MaxRecursionLevel = 100;
  3384.     }
  3385.  
  3386.         // Now for the cosmic flame dots
  3387.  
  3388.     MaxFlamePoints = ToolValue(ToolTypes,"MAXDOTS",Array[ARG_MAXDOTS] ? *(LONG *)Array[ARG_MAXDOTS] : 20000);
  3389.  
  3390.     MaxFlamePoints /= 100;
  3391.  
  3392.     if(MaxFlamePoints < 10)
  3393.         MaxFlamePoints = 10;
  3394.     else
  3395.     {
  3396.         if(MaxFlamePoints > 1000)
  3397.             MaxFlamePoints = 1000;
  3398.     }
  3399.  
  3400.         // Create the commodities interface
  3401.  
  3402.     if(Error = SetupCx())
  3403.     {
  3404.         if(Error != ERR_Duplicate)
  3405.             ReportError(NULL,NULL,Error);
  3406.  
  3407.         if(Args)
  3408.             FreeArgs(Args);
  3409.  
  3410.         if(Icon)
  3411.             FreeDiskObject(Icon);
  3412.  
  3413.         CloseAll(RETURN_FAIL);
  3414.     }
  3415.  
  3416.         // Pop up the control panel if necessary
  3417.  
  3418.     if(MatchToolValue(ToolString(ToolTypes,"CX_POPUP",Array[ARG_POPUP] ? Array[ARG_POPUP] : (STRPTR)"no"),"yes"))
  3419.     {
  3420.         PopUp = TRUE;
  3421.  
  3422.         SetupWindow();
  3423.     }
  3424.  
  3425.         // Clean up
  3426.  
  3427.     if(Args)
  3428.         FreeArgs(Args);
  3429.  
  3430.     if(Icon)
  3431.         FreeDiskObject(Icon);
  3432. }
  3433.  
  3434.     /* UpdateModeString():
  3435.      *
  3436.      *    This routine builds the screen mode and screen depth string
  3437.      *    for the user interface.
  3438.      */
  3439.  
  3440. VOID
  3441. UpdateModeString()
  3442. {
  3443.     WORD Len;
  3444.  
  3445.     if(!GetModeName(DisplayID,DisplayModeBuffer))
  3446.         strcpy(DisplayModeBuffer,"«Default screen mode»");
  3447.  
  3448.     Len = strlen(DisplayModeBuffer);
  3449.  
  3450.     if(Depth)
  3451.         SPrintf(&DisplayModeBuffer[Len],", %ld colours",1L << Depth);
  3452.     else
  3453.         strcpy(&DisplayModeBuffer[Len],", «Maximum depth»");
  3454. }
  3455.  
  3456.     /* SaveOptions(char **argv):
  3457.      *
  3458.      *    Here we store the current options within the program icon.
  3459.      */
  3460.  
  3461. VOID
  3462. SaveOptions(char **argv)
  3463. {
  3464.     STATIC STRPTR KnownTypes[] =
  3465.     {
  3466.         "CX_PRIORITY",
  3467.         "CX_POPKEY",
  3468.         "CX_POPUP",
  3469.         "BLANKSCREEN",
  3470.         "SAVESCREEN",
  3471.         "FRACTAL",
  3472.         "COLOUR",
  3473.         "DISPLAYMODE",
  3474.         "DEPTH",
  3475.         "SCREENTIMEOUT",
  3476.         "PATTERNTIMEOUT",
  3477.         "MAXRECURSION",
  3478.         "MAXDOTS"
  3479.     };
  3480.  
  3481.     struct WBStartup    *Startup = (struct WBStartup *)argv;
  3482.     BPTR             OldDir;
  3483.     struct DiskObject    *Icon;
  3484.  
  3485.     OldDir = CurrentDir(MainProcess -> pr_HomeDir);
  3486.  
  3487.         // Get the program icon
  3488.  
  3489.     if(Icon = GetDiskObject(Startup -> sm_ArgList -> wa_Name))
  3490.     {
  3491.         STRPTR    *Types,
  3492.             *NewTypes,
  3493.              Data;
  3494.         LONG     Count = 0,Known = sizeof(KnownTypes) / sizeof(STRPTR),Len = 0,i;
  3495.  
  3496.             // Count the number of tooltypes present
  3497.  
  3498.         if(Types = (STRPTR *)Icon -> do_ToolTypes)
  3499.         {
  3500.             while(Types[Count])
  3501.                 Count++;
  3502.         }
  3503.  
  3504.             // Count the room required for the tooltypes to add
  3505.  
  3506.         for(i = 0 ; i < Known ; i++)
  3507.             Len += strlen(KnownTypes[i]) + 2;
  3508.  
  3509.             // Add room for the keys
  3510.  
  3511.         Len += (10) + (256) + (4) + (256) + (256) + (8) + (8) + (40) + (10) + (10) + (10) + (10) + (10);
  3512.  
  3513.             // All the data will go here
  3514.  
  3515.         if(NewTypes = (STRPTR *)AllocVec(Len + (Count + 1 + Known) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  3516.         {
  3517.             STRPTR    *Tool = NewTypes,String;
  3518.             UBYTE    LocalBuffer[DISPLAYNAMELEN];
  3519.  
  3520.             Data = (STRPTR)&NewTypes[Count + 1 + Known];
  3521.  
  3522.                 // CX_PRIORITY=[..]
  3523.  
  3524.             SPrintf(Data,"CX_PRIORITY=%ld",NewBroker . nb_Pri);
  3525.  
  3526.             *Tool++ = Data;
  3527.             Data += strlen(Data) + 1;
  3528.  
  3529.                 // CX_POPKEY=[..]
  3530.  
  3531.             SPrintf(Data,"CX_POPKEY=%s",HotkeyBuffer);
  3532.  
  3533.             *Tool++ = Data;
  3534.             Data += strlen(Data) + 1;
  3535.  
  3536.                 // CX_POPUP=[..]
  3537.  
  3538.             SPrintf(Data,"CX_POPUP=%s",PopUp ? "yes" : "no");
  3539.  
  3540.             *Tool++ = Data;
  3541.             Data += strlen(Data) + 1;
  3542.  
  3543.                 // BLANKSCREEN=[..]
  3544.  
  3545.             SPrintf(Data,"BLANKSCREEN=%s",BlankScreenBuffer);
  3546.  
  3547.             *Tool++ = Data;
  3548.             Data += strlen(Data) + 1;
  3549.  
  3550.                 // SAVESCREEN=[..]
  3551.  
  3552.             SPrintf(Data,"SAVESCREEN=%s",SaveScreenBuffer);
  3553.  
  3554.             *Tool++ = Data;
  3555.             Data += strlen(Data) + 1;
  3556.  
  3557.                 // FRACTAL=[..]
  3558.  
  3559.             switch(FractalType)
  3560.             {
  3561.                 case FRACTAL_REAL_PLANE:
  3562.  
  3563.                     String = "REALPLANE";
  3564.                     break;
  3565.  
  3566.                 case FRACTAL_COSMIC_FLAME:
  3567.  
  3568.                     String = "COSMICFLAME";
  3569.                     break;
  3570.  
  3571.                 case FRACTAL_RANDOM:
  3572.  
  3573.                     String = "RANDOM";
  3574.                     break;
  3575.             }
  3576.  
  3577.             SPrintf(Data,"FRACTAL=%s",String);
  3578.  
  3579.             *Tool++ = Data;
  3580.             Data += strlen(Data) + 1;
  3581.  
  3582.                 // COLOUR=[..]
  3583.  
  3584.             switch(ColourMode)
  3585.             {
  3586.                 case COLOUR_CYCLE:
  3587.  
  3588.                     String = "CYCLE";
  3589.                     break;
  3590.  
  3591.                 case COLOUR_STATIC:
  3592.  
  3593.                     String = "STATIC";
  3594.                     break;
  3595.             }
  3596.  
  3597.             SPrintf(Data,"COLOUR=%s",String);
  3598.  
  3599.             *Tool++ = Data;
  3600.             Data += strlen(Data) + 1;
  3601.  
  3602.                 // DISPLAYMODE=[..]
  3603.  
  3604.             if(GetModeName(DisplayID,LocalBuffer))
  3605.             {
  3606.                 SPrintf(Data,"DISPLAYMODE=%s",LocalBuffer);
  3607.  
  3608.                 *Tool++ = Data;
  3609.                 Data += strlen(Data) + 1;
  3610.             }
  3611.  
  3612.                 // DEPTH=[..]
  3613.  
  3614.             SPrintf(Data,"DEPTH=%ld",Depth);
  3615.  
  3616.             *Tool++ = Data;
  3617.             Data += strlen(Data) + 1;
  3618.  
  3619.                 // SCREENTIMEOUT=[..]
  3620.  
  3621.             SPrintf(Data,"SCREENTIMEOUT=%ld:%02ld",ScreenTimeout / 60,ScreenTimeout % 60);
  3622.  
  3623.             *Tool++ = Data;
  3624.             Data += strlen(Data) + 1;
  3625.  
  3626.                 // PATTERNTIMEOUT=[..]
  3627.  
  3628.             SPrintf(Data,"PATTERNTIMEOUT=%ld:%02ld",PatternTimeout / 60,PatternTimeout % 60);
  3629.  
  3630.             *Tool++ = Data;
  3631.             Data += strlen(Data) + 1;
  3632.  
  3633.                 // MAXRECURSION=[..]
  3634.  
  3635.             SPrintf(Data,"MAXRECURSION=%ld",MaxRecursionLevel);
  3636.  
  3637.             *Tool++ = Data;
  3638.             Data += strlen(Data) + 1;
  3639.  
  3640.                 // MAXDOTS=[..]
  3641.  
  3642.             SPrintf(Data,"MAXDOTS=%ld",MaxFlamePoints * 100);
  3643.  
  3644.             *Tool++ = Data;
  3645.  
  3646.                 // Now add the remaining old tooltypes,
  3647.                 // unless we already took care of them
  3648.  
  3649.             if(Types = (STRPTR *)Icon -> do_ToolTypes)
  3650.             {
  3651.                 BOOL GotIt;
  3652.  
  3653.                 while(*Types)
  3654.                 {
  3655.                     GotIt = FALSE;
  3656.  
  3657.                     for(i = 0 ; i < Known ; i++)
  3658.                     {
  3659.                         if(!Strnicmp(*Types,KnownTypes[i],strlen(KnownTypes[i])))
  3660.                         {
  3661.                             GotIt = TRUE;
  3662.  
  3663.                             break;
  3664.                         }
  3665.                     }
  3666.  
  3667.                     if(!GotIt)
  3668.                         *Tool++ = *Types;
  3669.  
  3670.                     Types++;
  3671.                 }
  3672.             }
  3673.  
  3674.                 // Install the new tooltypes
  3675.  
  3676.             Icon -> do_ToolTypes = (char **)NewTypes;
  3677.  
  3678.                 // Write the icon
  3679.  
  3680.             if(!PutDiskObject(Startup -> sm_ArgList -> wa_Name,Icon))
  3681.                 ReportError(Window,"Error writing icon\n%s",IoErr());
  3682.  
  3683.                 // Clean up
  3684.  
  3685.             FreeVec(NewTypes);
  3686.         }
  3687.         else
  3688.             ReportError(Window,NULL,ERROR_NO_FREE_STORE);
  3689.  
  3690.         FreeDiskObject(Icon);
  3691.     }
  3692.     else
  3693.         ReportError(Window,"Error reading icon\n%s",IoErr());
  3694.  
  3695.     CurrentDir(OldDir);
  3696. }
  3697.  
  3698.     /* main(int argc,char **argv):
  3699.      *
  3700.      *    That's where all the trouble starts.
  3701.      */
  3702.  
  3703. void __stdargs
  3704. main(int argc,char **argv)
  3705. {
  3706.     ULONG    SignalSet;
  3707.     BOOL    Done = FALSE;
  3708.  
  3709.         // Open everything we need
  3710.  
  3711.     OpenAll(argc,argv);
  3712.  
  3713.         // Go into loop waiting for messages
  3714.  
  3715.     do
  3716.     {
  3717.             // Wait for a signal...
  3718.  
  3719.         SignalSet = SIG_CX | SIG_BREAK | SIG_WAKEUP;
  3720.  
  3721.         if(Window)
  3722.             SignalSet |= SIG_WINDOW;
  3723.  
  3724.         SignalSet = Wait(SignalSet);
  3725.  
  3726.             // Check the commodities toolkit reply port
  3727.  
  3728.         if(SignalSet & SIG_CX)
  3729.         {
  3730.             CxMsg *Message;
  3731.  
  3732.             while(Message = (CxMsg *)GetMsg(CxPort))
  3733.                 HandleCxMsg(Message);
  3734.         }
  3735.  
  3736.             // ^C tells the program to quit
  3737.  
  3738.         if(SignalSet & SIG_BREAK)
  3739.             Done = TRUE;
  3740.  
  3741.             // ^F tells the program to open its control panel
  3742.  
  3743.         if(SignalSet & SIG_WAKEUP)
  3744.             SetupWindow();
  3745.  
  3746.             // If the control panel is still open,
  3747.             // check for new messages.
  3748.  
  3749.         if(Window)
  3750.         {
  3751.             if(SignalSet & SIG_WINDOW)
  3752.             {
  3753.                 struct IntuiMessage    *IMsg;
  3754.                 BOOL             Hide = FALSE;
  3755.                 ULONG             MsgClass;
  3756.                 struct Gadget        *MsgGadget;
  3757.                 ULONG             LocalID,LocalDepth;
  3758.                 IX             Expression;
  3759.                 BOOL             NewKeys;
  3760.                 STRPTR             String;
  3761.                 LONG             Error;
  3762.                 struct IBox         Box;
  3763.  
  3764.                 while(IMsg = LT_GetIMsg(Handle))
  3765.                 {
  3766.                     MsgClass    = IMsg -> Class;
  3767.                     MsgGadget    = (struct Gadget *)IMsg -> IAddress;
  3768.  
  3769.                     LT_ReplyIMsg(IMsg);
  3770.  
  3771.                     switch(MsgClass)
  3772.                     {
  3773.                         case IDCMP_CLOSEWINDOW:
  3774.  
  3775.                             Hide = TRUE;
  3776.                             break;
  3777.  
  3778.                         case IDCMP_GADGETUP:
  3779.  
  3780.                             switch(MsgGadget -> GadgetID)
  3781.                             {
  3782.                                 case GAD_QUIT:
  3783.  
  3784.                                     Done = TRUE;
  3785.                                     break;
  3786.  
  3787.                                     // Make sure that the key
  3788.                                     // codes are correct
  3789.  
  3790.                                 case GAD_BLANKSCREEN:
  3791.                                 case GAD_SAVESCREEN:
  3792.                                 case GAD_HOTKEY:
  3793.  
  3794.                                     if(ParseIX(LT_GetString(Handle,MsgGadget -> GadgetID),&Expression))
  3795.                                     {
  3796.                                         DisplayBeep(Window -> WScreen);
  3797.  
  3798.                                         LT_Activate(Handle,MsgGadget -> GadgetID);
  3799.                                     }
  3800.  
  3801.                                     break;
  3802.  
  3803.                                 case GAD_HIDE:
  3804.                                 case GAD_SAVE:
  3805.  
  3806.                                     LT_LockWindow(Window);
  3807.  
  3808.                                         // Update the Commodities
  3809.                                         // interface only if the
  3810.                                         // key assignments have
  3811.                                         // changed
  3812.  
  3813.                                     NewKeys = FALSE;
  3814.  
  3815.                                     String = LT_GetString(Handle,GAD_HOTKEY);
  3816.  
  3817.                                     if(!ParseIX(String,&Expression))
  3818.                                     {
  3819.                                         IX OldExpression;
  3820.  
  3821.                                         ParseIX(HotkeyBuffer,&OldExpression);
  3822.  
  3823.                                         if(memcmp(&Expression,&OldExpression,sizeof(IX)))
  3824.                                         {
  3825.                                             SpecialQualifier = SubQualifier(HotkeyBuffer,SpecialQualifier);
  3826.  
  3827.                                             strcpy(HotkeyBuffer,String);
  3828.  
  3829.                                             SpecialQualifier = AddQualifier(HotkeyBuffer,SpecialQualifier);
  3830.  
  3831.                                             NewKeys = TRUE;
  3832.                                         }
  3833.                                     }
  3834.  
  3835.                                     String = LT_GetString(Handle,GAD_BLANKSCREEN);
  3836.  
  3837.                                     if(!ParseIX(String,&Expression))
  3838.                                     {
  3839.                                         IX OldExpression;
  3840.  
  3841.                                         ParseIX(BlankScreenBuffer,&OldExpression);
  3842.  
  3843.                                         if(memcmp(&Expression,&OldExpression,sizeof(IX)))
  3844.                                         {
  3845.                                             SpecialQualifier = SubQualifier(BlankScreenBuffer,SpecialQualifier);
  3846.  
  3847.                                             strcpy(BlankScreenBuffer,String);
  3848.  
  3849.                                             SpecialQualifier = AddQualifier(BlankScreenBuffer,SpecialQualifier);
  3850.  
  3851.                                             NewKeys = TRUE;
  3852.                                         }
  3853.                                     }
  3854.  
  3855.                                     String = LT_GetString(Handle,GAD_SAVESCREEN);
  3856.  
  3857.                                     if(!ParseIX(String,&Expression))
  3858.                                     {
  3859.                                         IX OldExpression;
  3860.  
  3861.                                         ParseIX(SaveScreenBuffer,&OldExpression);
  3862.  
  3863.                                         if(memcmp(&Expression,&OldExpression,sizeof(IX)))
  3864.                                         {
  3865.                                             SpecialQualifier = SubQualifier(SaveScreenBuffer,SpecialQualifier);
  3866.  
  3867.                                             strcpy(SaveScreenBuffer,String);
  3868.  
  3869.                                             SpecialQualifier = AddQualifier(SaveScreenBuffer,SpecialQualifier);
  3870.  
  3871.                                             NewKeys = TRUE;
  3872.                                         }
  3873.                                     }
  3874.  
  3875.                                     LT_UnlockWindow(Window);
  3876.  
  3877.                                     if(NewKeys)
  3878.                                     {
  3879.                                         if(Error = SetupCx())
  3880.                                         {
  3881.                                             if(Error != ERR_Duplicate)
  3882.                                                 ReportError(Window,NULL,Error);
  3883.  
  3884.                                             CloseAll(RETURN_FAIL);
  3885.                                         }
  3886.                                     }
  3887.  
  3888.                                     if(MsgGadget -> GadgetID == GAD_HIDE)
  3889.                                         Hide = TRUE;
  3890.                                     else
  3891.                                         SaveOptions(argv);
  3892.  
  3893.                                     break;
  3894.                             }
  3895.  
  3896.                             break;
  3897.  
  3898.                             // Pick a new display mode
  3899.  
  3900.                         case IDCMP_IDCMPUPDATE:
  3901.  
  3902.                             if(DisplayID == INVALID_ID)
  3903.                                 LocalID = GetVPModeID(&Window -> WScreen -> ViewPort);
  3904.                             else
  3905.                                 LocalID = DisplayID;
  3906.  
  3907.                             if(Depth)
  3908.                                 LocalDepth = Depth;
  3909.                             else
  3910.                             {
  3911.                                 struct DimensionInfo DimensionInfo;
  3912.  
  3913.                                 if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(DimensionInfo),DTAG_DIMS,LocalID))
  3914.                                     LocalDepth = DimensionInfo . MaxDepth;
  3915.                                 else
  3916.                                     LocalDepth = 2;
  3917.                             }
  3918.  
  3919.                             if(ScreenModeRequest -> sm_UserData && !ResetRequest)
  3920.                                 CopyMem(&ScreenModeRequest -> sm_LeftEdge,&Box,sizeof(struct IBox));
  3921.                             else
  3922.                             {
  3923.                                 CopyMem(&Window -> LeftEdge,&Box,sizeof(struct IBox));
  3924.  
  3925.                                 Box . Top    += Window -> BorderTop;
  3926.                                 Box . Height    -= Window -> BorderTop;
  3927.                             }
  3928.  
  3929.                             if(AslRequestTags(ScreenModeRequest,
  3930.                                 ASLSM_Window,            Window,
  3931.                                 ASLSM_SleepWindow,        TRUE,
  3932.                                 ASLSM_InitialDisplayID,        LocalID,
  3933.                                 ASLSM_InitialDisplayDepth,    LocalDepth,
  3934.                                 ASLSM_UserData,            TRUE,
  3935.                                 ASLSM_InitialLeftEdge,        Box . Left,
  3936.                                 ASLSM_InitialTopEdge,        Box . Top,
  3937.                                 ASLSM_InitialWidth,        Box . Width,
  3938.                                 ASLSM_InitialHeight,        Box . Height,
  3939.                             TAG_DONE))
  3940.                             {
  3941.                                 ResetRequest = FALSE;
  3942.  
  3943.                                 DisplayID    = ScreenModeRequest -> sm_DisplayID;
  3944.                                 Depth        = ScreenModeRequest -> sm_DisplayDepth;
  3945.  
  3946.                                 UpdateModeString();
  3947.  
  3948.                                 LT_SetAttributes(Handle,GAD_MODE,
  3949.                                     GTTX_Text,    DisplayModeBuffer,
  3950.                                 TAG_DONE);
  3951.                             }
  3952.                             else
  3953.                                 ResetRequest = TRUE;
  3954.  
  3955.                             break;
  3956.                     }
  3957.                 }
  3958.  
  3959.                 if(Hide)
  3960.                     ShutdownWindow();
  3961.             }
  3962.         }
  3963.     }
  3964.     while(!Done);
  3965.  
  3966.     CloseAll(RETURN_OK);
  3967. }
  3968.